Created
April 5, 2026 19:14
-
-
Save sumkincpp/e73625758b5ab44e9a33a8aaa2ae21ba to your computer and use it in GitHub Desktop.
Extension Fingerprint Blocker (LinkedIn) Plugin for TamperMonkey
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Extension Fingerprint Blocker (LinkedIn) | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.0 | |
| // @description Blocks LinkedIn from detecting installed Chrome extensions | |
| // @author Anonymous | |
| // @match *://*.linkedin.com/* | |
| // @match *://linkedin.com/* | |
| // @grant none | |
| // @run-at document-start | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| const EXTENSION_PROTOCOL = 'chrome-extension://'; | |
| const MOZ_EXTENSION_PROTOCOL = 'moz-extension://'; | |
| function isExtensionUrl(url) { | |
| if (!url) return false; | |
| const urlStr = String(url); | |
| return urlStr.startsWith(EXTENSION_PROTOCOL) || | |
| urlStr.startsWith(MOZ_EXTENSION_PROTOCOL); | |
| } | |
| function createFailedPromise() { | |
| return Promise.reject(new TypeError('Failed to fetch')); | |
| } | |
| const originalFetch = window.fetch; | |
| window.fetch = function(resource, init) { | |
| let url = ''; | |
| if (typeof resource === 'string') { | |
| url = resource; | |
| } else if (resource instanceof Request) { | |
| url = resource.url; | |
| } else if (resource && resource.toString) { | |
| url = resource.toString(); | |
| } | |
| if (isExtensionUrl(url)) { | |
| return createFailedPromise(); | |
| } | |
| return originalFetch.apply(this, arguments); | |
| }; | |
| const originalXhrOpen = XMLHttpRequest.prototype.open; | |
| XMLHttpRequest.prototype.open = function(method, url) { | |
| if (isExtensionUrl(url)) { | |
| this._blockedExtensionRequest = true; | |
| } | |
| return originalXhrOpen.apply(this, arguments); | |
| }; | |
| const originalXhrSend = XMLHttpRequest.prototype.send; | |
| XMLHttpRequest.prototype.send = function() { | |
| if (this._blockedExtensionRequest) { | |
| const self = this; | |
| setTimeout(function() { | |
| Object.defineProperty(self, 'status', { value: 0, writable: false }); | |
| Object.defineProperty(self, 'statusText', { value: '', writable: false }); | |
| Object.defineProperty(self, 'responseText', { value: '', writable: false }); | |
| Object.defineProperty(self, 'response', { value: '', writable: false }); | |
| Object.defineProperty(self, 'readyState', { value: 4, writable: false }); | |
| const errorEvent = new ProgressEvent('error'); | |
| self.dispatchEvent(errorEvent); | |
| if (typeof self.onerror === 'function') { | |
| self.onerror(errorEvent); | |
| } | |
| const loadendEvent = new ProgressEvent('loadend'); | |
| self.dispatchEvent(loadendEvent); | |
| if (typeof self.onloadend === 'function') { | |
| self.onloadend(loadendEvent); | |
| } | |
| }, 0); | |
| return; | |
| } | |
| return originalXhrSend.apply(this, arguments); | |
| }; | |
| const originalImage = window.Image; | |
| window.Image = function(width, height) { | |
| const img = new originalImage(width, height); | |
| const originalSrcDescriptor = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, 'src') || | |
| Object.getOwnPropertyDescriptor(img.__proto__, 'src'); | |
| Object.defineProperty(img, 'src', { | |
| get: function() { | |
| return originalSrcDescriptor.get.call(this); | |
| }, | |
| set: function(value) { | |
| if (isExtensionUrl(value)) { | |
| setTimeout(() => { | |
| const errorEvent = new Event('error'); | |
| this.dispatchEvent(errorEvent); | |
| if (typeof this.onerror === 'function') { | |
| this.onerror(errorEvent); | |
| } | |
| }, 0); | |
| return; | |
| } | |
| return originalSrcDescriptor.set.call(this, value); | |
| }, | |
| configurable: true | |
| }); | |
| return img; | |
| }; | |
| window.Image.prototype = originalImage.prototype; | |
| const originalCreateElement = document.createElement.bind(document); | |
| document.createElement = function(tagName, options) { | |
| const element = originalCreateElement(tagName, options); | |
| if (tagName.toLowerCase() === 'img') { | |
| const originalSrcDescriptor = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, 'src'); | |
| if (originalSrcDescriptor) { | |
| Object.defineProperty(element, 'src', { | |
| get: function() { | |
| return originalSrcDescriptor.get.call(this); | |
| }, | |
| set: function(value) { | |
| if (isExtensionUrl(value)) { | |
| setTimeout(() => { | |
| const errorEvent = new Event('error'); | |
| this.dispatchEvent(errorEvent); | |
| if (typeof this.onerror === 'function') { | |
| this.onerror(errorEvent); | |
| } | |
| }, 0); | |
| return; | |
| } | |
| return originalSrcDescriptor.set.call(this, value); | |
| }, | |
| configurable: true | |
| }); | |
| } | |
| } | |
| if (tagName.toLowerCase() === 'script' || tagName.toLowerCase() === 'link') { | |
| const attrName = tagName.toLowerCase() === 'script' ? 'src' : 'href'; | |
| const proto = tagName.toLowerCase() === 'script' ? HTMLScriptElement.prototype : HTMLLinkElement.prototype; | |
| const originalDescriptor = Object.getOwnPropertyDescriptor(proto, attrName); | |
| if (originalDescriptor) { | |
| Object.defineProperty(element, attrName, { | |
| get: function() { | |
| return originalDescriptor.get.call(this); | |
| }, | |
| set: function(value) { | |
| if (isExtensionUrl(value)) { | |
| setTimeout(() => { | |
| const errorEvent = new Event('error'); | |
| this.dispatchEvent(errorEvent); | |
| if (typeof this.onerror === 'function') { | |
| this.onerror(errorEvent); | |
| } | |
| }, 0); | |
| return; | |
| } | |
| return originalDescriptor.set.call(this, value); | |
| }, | |
| configurable: true | |
| }); | |
| } | |
| } | |
| return element; | |
| }; | |
| const originalSetAttribute = Element.prototype.setAttribute; | |
| Element.prototype.setAttribute = function(name, value) { | |
| const lowerName = name.toLowerCase(); | |
| if ((lowerName === 'src' || lowerName === 'href') && isExtensionUrl(value)) { | |
| setTimeout(() => { | |
| const errorEvent = new Event('error'); | |
| this.dispatchEvent(errorEvent); | |
| if (typeof this.onerror === 'function') { | |
| this.onerror(errorEvent); | |
| } | |
| }, 0); | |
| return; | |
| } | |
| return originalSetAttribute.apply(this, arguments); | |
| }; | |
| if (window.navigator && window.navigator.sendBeacon) { | |
| const originalSendBeacon = window.navigator.sendBeacon.bind(window.navigator); | |
| window.navigator.sendBeacon = function(url, data) { | |
| if (isExtensionUrl(url)) { | |
| return false; | |
| } | |
| return originalSendBeacon(url, data); | |
| }; | |
| } | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment