Back to all posts
Published on · by Renaud Deraison

LinkedIn's BrowserGate, and why one browser identity is no longer enough

LinkedIn quietly probes for 6,000+ browser extensions, harvests 48 device attributes, and pulls your LAN IP via WebRTC on every visit. The fix is not a privacy setting — it is a different shape of browser.

Every time you open LinkedIn, the page silently asks your browser a few thousand questions — which extensions are installed, which fonts, which GPU, which CPU core count, which local IP address. Then it writes the answers into a header it attaches to every subsequent request. You did not agree to this, and you cannot see it happen. It is not a bug; it is called "Spectroscopy."

In early April, a European LinkedIn-users' group called Fairlinked e.V. published an investigation that, depending on how you count, was either the most detailed or the least surprising browser-fingerprinting story of the decade. LinkedIn's own front-end JavaScript, they showed, fires between six and seven thousand fetch() requests at chrome-extension:// URLs every time you load the site, tests whether each one resolves, collects 48 other device and browser characteristics, and ships the whole bundle — RSA-encrypted, attached to every subsequent API call — back to LinkedIn's telemetry endpoint.

The reporting was picked up by The Next Web, independently verified by 404 Privacy, and reverse-engineered at the code level in a long technical breakdown that walks through the actual payloads. Fairlinked's sister organisation, Teamfluence Signal Systems, had already filed a preliminary injunction in Munich in January 2026 under the EU's Digital Markets Act (DMA — the European regulation that governs how gatekeeper platforms must treat users). The court denied it. LinkedIn, for its part, told reporters that the claims are "plain wrong" and that its scanning only targets extensions that violate its terms of service.

This post is not about whether LinkedIn is within its legal rights in Ireland or Germany. It is about what the story illustrates: the browser you are reading this in was never designed to push back on this kind of thing, and — more importantly — cannot push back on it, because it only has one identity to give.

What the page actually does when you visit linkedin.com

There are two mechanisms running in parallel, and they are worth understanding even if you never open a DevTools panel.

Active extension detection. The page ships a hard-coded list of 6,000+ Chrome extension IDs. For each one, it fires a fetch() to a known file inside that extension's package — chrome-extension://<id>/manifest.json, say, or a specific icon. If the fetch succeeds, the extension is installed; if Chrome rejects the request, it is not. The trick only works on extensions that expose at least one "web-accessible resource," which most real extensions do. The article reports that a stealth variant uses window.requestIdleCallback() with staggered delays to avoid lighting up the network panel.

Passive DOM scanning ("Spectroscopy"). Separately, the page walks your DOM looking for chrome-extension:// URL references. This catches extensions that inject content into the page — the ones the hard-coded list might have missed, or newer ones that the list has not yet learned about.

The results feed a fingerprinting pipeline LinkedIn calls APFC internally, for "Anti-fraud Platform Features Collection," with a secondary name of DNA for "Device Network Analysis." Alongside the extension list, the pipeline collects:

Canvas fingerprint

The page draws a hidden picture using specific text, curves and colours, then reads the pixels back. The exact pixel values depend on your GPU driver, font rasterizer, and OS version — enough to produce a signature that is stable across page loads and rare enough to identify you on return visits.

WebGL renderer

Over 65 parameters describing your graphics stack: vendor string, driver version, supported extensions, shader precision. A laptop and a desktop running the same OS produce different WebGL signatures.

Audio context

A fingerprint derived from running silent audio through the browser's oscillator and compressor nodes. Different audio stacks round off floating-point math slightly differently.

WebRTC local IP

WebRTC is the browser's real-time-calling API. A built-in side effect of how it discovers network routes is that it can be asked for your LAN IP address — the 192.168.x or 10.x number your router assigned you — even if you are behind a VPN. LinkedIn asks.

Hardware & locale

CPU core count, device memory, screen resolution and pixel ratio, timezone, language, battery level and discharge time, installed fonts, touch support. Forty-eight attributes in total according to the Fairlinked write-up.

And the extension list

The thousands-wide probe described above. Most fingerprinting papers treat "installed extensions" as a nice-to-have; LinkedIn treats it as the headline signal.

These signals are combined into an encrypted blob and attached as an HTTP header to every subsequent API request the page makes — so LinkedIn's backend always knows, at every hop, which exact device you are. The investigation reports that LinkedIn has taken action — account suspensions, warnings — against users running extensions it does not like, which is the most direct evidence that the data is in fact used and not merely collected.

Extension scan6,000+ chrome-extension:// probesSpectroscopyDOM walk for injected URLsCanvas fingerprinthidden image, pixel read-backWebGL + audio65+ GPU params, oscillatorWebRTC local IPLAN address, even behind VPNHardware + localeCPU, RAM, screen, fonts, batteryAPFC / DNACompositefingerprintRSA-encryptedattached as headerto every API callLINKEDINli/tracktelemetryendpointAll six signals collected on a single page load. The composite rides along on every subsequent request.
What one page load of linkedin.com actually does. The page tests 6,000+ extensions, walks the DOM for more, collects 48 hardware and browser attributes, and asks WebRTC for your LAN IP. The combined blob is attached to every later request as an HTTP header.

There is a real question buried under the legal one: if LinkedIn is doing this at this scale, how many other sites are doing a smaller version? The honest answer is: most of the big ones. LinkedIn is unusual only in the breadth of its extension list and the care with which it was engineered. The rest of the consumer web runs the same basic playbook at varying levels of sophistication.

The problem is not fingerprinting. It is identity reuse.

Take a step back. Canvas, WebGL, WebRTC, font enumeration — these are not new. Every security researcher in the last ten years has written an essay that ends with "turn on Firefox's resistFingerprinting" or "install CanvasBlocker." That advice is not wrong, exactly, but it misses the load-bearing wall of the problem.

Even if you had perfect fingerprinting resistance — every signal normalized, every canvas blank, every WebRTC connection refused — your browser still has one cookie jar, one history file, one set of logged-in sessions, one saved-passwords vault, one installed-extensions list, one IP address at the network layer. Everything you do on the web comes out of that one identity. A fingerprinter that cannot read your canvas can still tell that the person who logged into LinkedIn, the person who logged into Facebook, the person who looked at a small independent bookshop, and the person who checked their health portal all came from the same browser instance with the same cookies from the same IP. And the network effect is cross-site: LinkedIn's data becomes more useful the moment it is joined with any other site's.

This is why a lone anti-fingerprinting extension does not really fix the problem, and why "use a VPN" on top of an ordinary browser does not fix it either. A VPN changes your apparent IP, but it does not split your browser into multiple identities. You still have one cookie jar. You still have one set of sessions. LinkedIn and Facebook still see the same machine — and now, usefully for them, a machine that has been cross-checked against a VPN's IP history.

The per-tab VPN argument

Here is the part that starts to feel different. Because every Bromure tab is its own disposable Linux virtual machine, the VPN belongs to the tab, not to the whole browser. Not to the whole computer. To the tab.

You can attach a Mullvad endpoint in Sweden to your LinkedIn profile, a ProtonVPN endpoint in Switzerland to your Facebook profile, Cloudflare WARP to a "random links" profile, and nothing at all to your local banking profile — all at the same time, on the same Mac, in the same Bromure app. LinkedIn sees the Swedish exit. Facebook sees the Swiss exit. The bank sees your actual home connection. None of them has a clean way to notice they are looking at the same person's laptop.

Traditional browser — one identityLinkedInlogged inFacebooklogged inBanklogged inSHARED ACROSS ALL TABS• one cookie jar• one saved-passwords vault• one extension list• one WebRTC stack — LAN IP leaks• one IP address (one VPN, at most)FINGERPRINTERall three tabs → same usercross-site identity trivially joinedBromure — per-tab VM, per-tab VPNVM · LINKEDINLinkedInVPN: SwedenWebRTC: offown cookiesVM · FACEBOOKFacebookVPN: SwitzerlandWebRTC: offown cookiesVM · BANKBankno VPNWebRTC: offown cookiesSHARED: NONE• separate cookies per VM• separate extensions (or none)• separate IP address per VMclose the window → VM destroyedFINGERPRINTEReach VM looks like a different person
On the left, a traditional browser: every tab shares one cookie jar, one WebRTC stack, one IP address. Fingerprinters correlate across all of them. On the right, Bromure: each tab is its own VM with its own VPN, WebRTC is off by default, and the machines are wiped when the window closes.

This is not a theoretical separation. Bromure boots a real Linux kernel per tab, using Apple's Virtualization.framework. Each VM has its own kernel network stack, its own /etc/hosts, its own process tree, its own set of Chromium flags, its own profile directory on its own virtual disk. Two tabs on two fingerprinting sites, served by two different VPN endpoints, are indistinguishable from two separate people using two separate laptops, because at the layer fingerprinting operates, they are.

The per-tab VPN setting lives under the profile's VPN & Ads panel, with three options: Cloudflare WARP (Cloudflare's consumer encryption service), WireGuard (any provider, any self-hosted server — paste in a .conf), or IKEv2 (for corporate VPNs). The VPN runs inside the VM, which means even the guest Chromium process does not see your real IP.

Bromure disables WebRTC by default

WebRTC is the direct cause of the LAN-IP leak in BrowserGate. It was designed for browser-to-browser video and audio calls and, as a side effect of how it discovers network paths, it can be asked to enumerate your local network interfaces. Any site — not just the ones you are calling — can run that enumeration in the background and learn things like "this user's router handed them 192.168.1.47, so they are on a typical home network, which is the same range as last visit from this fingerprint."

Bromure turns WebRTC off by default for any profile that does not have both webcam and microphone enabled. Concretely, when a profile does not need webcam or microphone access, the Bromure launcher adds two Chromium flags:

  • --force-webrtc-ip-handling-policy=disable_non_proxied_udp
  • --enforce-webrtc-ip-permission-check

and loads a small browser extension called webrtc-block that replaces the RTCPeerConnection constructor with a no-op stub. That last part matters: the policy flag alone stops the IP from leaking over UDP, but a determined fingerprinter can still instantiate RTCPeerConnection and observe behaviour; the stub makes even the constructor fail. The net effect is that a site trying LinkedIn's LAN-IP trick, on a Bromure profile that does not need WebRTC, gets back nothing.

You do not need to toggle anything for this. It is the default state for any profile that does not have video-call hardware enabled. If you turn on webcam or microphone sharing in a profile's Media panel, the VPN and video-call use cases that need WebRTC come back automatically. The setting is "on only when you actually need it," which is closer to how the web was supposed to work.

What isolation does not fix

Two things worth naming up front. First, if you sign into LinkedIn with your real name from every profile, LinkedIn knows it is you. Isolation does not make you anonymous to services you voluntarily log into; it breaks cross-site identity joining and it stops passive re-identification between sessions. Those are real wins, but they are not anonymity.

Second, Bromure cannot stop LinkedIn from running its extension scan inside the Bromure VM. It can, and does, make the scan's results uninteresting: by default, a Bromure profile has no Chrome extensions installed other than Bromure's own internal ones, and those live on different, profile-scoped extension IDs that LinkedIn's hard-coded list does not include. The page dutifully probes 6,000 IDs; nothing comes back. The 48-attribute fingerprint is still collected — but it identifies one disposable VM whose WebRTC, cookies, and IP do not overlap with any other VM you run.

That is enough to defang BrowserGate as a cross-site correlation tool. It is not enough to hide you from LinkedIn once you are logged in, and we are not going to pretend otherwise.

Recommended Bromure settings for LinkedIn (and similar sites)

If you are setting up a dedicated LinkedIn profile, or a Facebook one, or any other social platform that is known to fingerprint aggressively, these are the defaults worth checking. Everything below is in the per-profile settings panel (gear icon next to the profile in the list).

General → Retain Browsing Data: ON

By default, Bromure destroys everything when you close the window, which is right for random browsing but wrong for a site you log in to every day. Turn this on so cookies and passwords survive between sessions on a dedicated virtual disk. You will not have to re-login every time.

Privacy & Safety → AI Phishing Detection: ON

LinkedIn phishing — fake recruiter messages linking to credential- harvest pages — is a large category. AI Phishing Detection sends the current page's URL, visible text, and form structure to Bromure's analysis server for scoring and warns you before you type into a fake form. Data leaves the local VM when this is enabled, which is worth knowing.

Media → Share Webcam: OFF

LinkedIn does not need your camera. Leaving webcam off also keeps WebRTC disabled, which is the direct mitigation for the local-IP leak the Fairlinked investigation documented.

Media → Share Microphone: OFF

Same reason. Webcam and microphone both need to be off for the automatic WebRTC kill-switch to engage (WebRTC is the API both of them depend on).

File Transfer → File Download: OFF

Normal LinkedIn use does not involve downloading files from LinkedIn. Turning downloads off means a compromised page cannot drop anything onto your Mac even if you click something you should not have. Leave File Upload on if you need to apply to jobs with a résumé.

VPN & Ads → WireGuard (or WARP): ON

This is the per-tab VPN argument in practice. Paste a WireGuard config for the exit you want LinkedIn to see (Mullvad, ProtonVPN, a self-hosted server), turn on Connect on Startup, and LinkedIn sees a different IP from every other tab you have open. WARP is the easier one-click option if you do not have a WireGuard provider already.

A few non-obvious notes. WebRTC is already off for this profile as long as webcam and microphone are both off — you do not need to set it anywhere, and there is no checkbox for it, because it is derived from those two settings.

If you are running a dedicated LinkedIn profile for work and want the VPN session to outlast individual tab closures, pair Retain Browsing Data with Connect on Startup under WireGuard — the VPN will come up automatically every time you reopen that profile.

You can take this further. The Advanced panel has an Encrypt Browsing Data option, which encrypts the persistent disk using LUKS with a key stored in the macOS Keychain. That is a reasonable level of paranoia for anything social-media adjacent that you nonetheless want to survive reboots.

The shape of the fix

BrowserGate is a good symbol for something that has been true for a while and is getting worse: ordinary browsers cannot push back meaningfully against this class of surveillance, because their entire architecture is built around a single identity per browser instance. You can install extensions to mitigate specific leaks, and you should; but the structural answer is a browser where each tab is its own computer, with its own network, its own privacy surface, and its own ability to end. Close the window, and that identity — whatever data LinkedIn's scanner collected, whatever correlation cookies attached — is gone.

That is the whole shape of the fix. It does not depend on LinkedIn agreeing to stop, and it does not depend on the DMA. It depends on your browser being a different shape than the one that was on the laptop you bought this with.