← back to blog

Extensions that quietly give a profile away

Most people building a multi-profile setup spend their time on the parts that get marketed hard: canvas noise, WebGL renderer strings, timezone matching, proxy quality. Extensions barely come up. That’s a mistake, because extensions are one of the few fingerprint surfaces that sit outside the browser engine itself, which means an antidetect browser’s spoofing layer often doesn’t touch them at all. You can have twenty profiles with twenty clean, distinct fingerprints and still hand a platform a single thread that ties them all together, because you installed the same four extensions on every one of them.

This is a practical writeup of how that leak actually works and what we do about it running proxy and cloud-phone infrastructure for account fleets out of Singapore.

How a site can even see your extensions

Browsers don’t expose a list of installed extensions to web pages by default, and that’s the assumption most people work from. But extensions themselves often break that wall without realizing it.

Chrome’s extension manifest has a field called web_accessible_resources. It lists files inside the extension (icons, injected scripts, CSS) that the extension allows any web page to fetch directly, using a URL like chrome-extension://<extension-id>/icon.png. A page can try to load that URL for every known extension ID in a list of thousands, and any request that succeeds tells the page you have that extension installed. This is not a theoretical exploit. It’s a documented technique that research projects and some fingerprinting vendors have built into detection scripts for years, because most popular ad blockers, password managers, and shopping assistants ship at least one resource this way.

The output of that probe is a set of extension IDs, which is functionally a second fingerprint layered on top of whatever the browser engine reports. Two profiles with identical canvas noise settings but different proxy IPs still look unrelated. Two profiles with the same six extension IDs, in the same order, look like the same person even if every other signal is randomized.

The extensions that leak the most

Not every extension is equally exposed. The riskier categories are the ones that touch the page directly:

  • Ad and content blockers inject CSS or hide DOM elements, and many expose rule files or icons through web_accessible_resources to render their own UI on the page.
  • Password managers and form fillers inject a content script into every page to detect login fields, and that script often loads styling or icons from the extension package.
  • Shopping and coupon extensions are usually the worst offenders, since their entire function is running on third-party retail pages and announcing themselves with a badge or popup.
  • VPN and “privacy” browser extensions are a special case worth calling out directly: several route only the tab’s HTTP traffic through their proxy while leaving WebRTC untouched, so a page can still pull your real IP through a STUN request even though the address bar shows a different exit IP. If you’re layering a VPN extension on top of a proxy configured at the browser or OS level, check what actually carries the WebRTC handshake before assuming they stack.

None of this makes the extension malicious. It’s just how the platform delivers its own UI, and the side effect is a detectable signature.

Sync is the quieter leak

Extension fingerprinting through web_accessible_resources gets attention because it’s dramatic and testable. The more common way operators actually get burned is duller: signing multiple browser profiles into the same Google account, or the same extension developer account, for sync convenience.

When Chrome sync is on, your installed extension list, their settings, and often bookmarks and saved passwords travel with the account, not the profile. If two “separate” profiles are both signed into the same sync account, or into accounts created in the same session with the same recovery email, that’s not a browser fingerprint problem at all, it’s an account graph problem, and it survives any amount of canvas or WebGL spoofing. This shows up constantly in setups where someone built ten clean antidetect profiles and then, out of habit, logged the extension into the same password manager vault or ad blocker license across all of them.

Why this matters more once you’re running a fleet

A single account doesn’t need to think about correlation. Fleets do, because platforms aren’t scoring your profile in isolation, they’re scoring it against every other session they’ve ever seen come from infrastructure that looks like yours. An identical extension set across dozens of profiles is exactly the kind of low-entropy signal that clustering systems are built to catch, because it doesn’t vary the way real, unrelated users’ browsers do. Real people install different combinations of extensions based on what they personally use. A fleet where every profile has the same ad blocker, the same password manager, and the same shopping extension, installed in the same order, looks manufactured because it is.

This is also where the proxy and browser layers can quietly undermine each other. Clean residential or mobile exit IPs and distinct device fingerprints buy you separation at the network and browser-engine level. If the extension layer is uniform across the fleet, you’ve built ten different front doors into the same room.

What we actually check before a profile goes into rotation

A few things we look at, none of which require special tooling beyond the browser’s own extension manager and dev tools:

Audit web_accessible_resources exposure. For any extension you’re considering standardizing across a fleet, unpack the .crx (or check its manifest on the Chrome Web Store listing) and see what it lists under web_accessible_resources. Some extensions expose nothing. Others expose their entire asset folder. That difference is the entire risk surface right there.

Vary the extension set, don’t clone it. Profiles don’t need to be extension-free to be safe, they need to not be identical to each other. Different profiles running different combinations of blockers, or none at all, produce the variance that real independent users would produce.

Keep sync scoped to the profile, not the operator. Each profile’s sync account, if used at all, should be its own account created for that profile, not a shared login across the fleet. This is a discipline problem more than a technical one, and it’s the leak we see people create for themselves most often.

Test WebRTC separately from the address bar. If a profile is running a VPN or proxy extension rather than a system-level or browser-level proxy, confirm the local candidate address it leaks by checking chrome://webrtc-internals or an equivalent test page, rather than trusting that the extension’s exit IP is the only IP the page ever sees.

Treat cloud phones as a separate surface with the same logic. On Android, the equivalent leak isn’t web_accessible_resources, it’s the installed package list, which apps can query and which stays identical across “different” devices if you clone the same app set onto every phone image. The principle carries over even though the mechanism is different.

The honest limit here

None of this guarantees a platform won’t flag an account, and nothing about extension hygiene changes what a platform decides to do with an account that trips other signals. What it does is close off one specific, well-documented correlation path that a lot of otherwise careful setups leave wide open, because the fingerprinting conversation usually stops at the browser engine and never gets to the extension layer sitting on top of it. Isolation is a stack, and the extension list is one more shelf in it, not the whole thing.

If you’re building out proxy and cloud-phone infrastructure for account work and want the isolation layer thought through end to end, take a look at what we run at Multi Account Ops.

Get new guides and videos first — join the Telegram channel.

need infra for this today?