Skip to content

Instantly share code, notes, and snippets.

@sumkincpp
Created April 5, 2026 19:14
Show Gist options
  • Select an option

  • Save sumkincpp/e73625758b5ab44e9a33a8aaa2ae21ba to your computer and use it in GitHub Desktop.

Select an option

Save sumkincpp/e73625758b5ab44e9a33a8aaa2ae21ba to your computer and use it in GitHub Desktop.
Extension Fingerprint Blocker (LinkedIn) Plugin for TamperMonkey
// ==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