Back to Blog
Fingerprint

Protocol Handler Detection: How Websites Detect Your Installed Apps

How URL protocol handlers like mailto: and slack: reveal installed applications for fingerprinting, and how to control protocol responses.

Introduction

Operating systems allow applications to register custom URL schemes, also known as protocol handlers. When an application like Slack, VS Code, Zoom, or Steam is installed, it registers a protocol (such as slack://, vscode://, zoommtg://, or steam://) that enables other applications and websites to launch it directly through a URL. This system powers deep linking, allowing a website to open a specific app view, join a meeting, or launch a game through a simple link click.

However, the mechanism that makes protocol handlers useful also makes them a fingerprinting surface. Websites can attempt to navigate to custom protocol URLs and observe the browser's response. The behavior differs depending on whether the protocol's associated application is installed: the browser may show a prompt to open the app, redirect silently, display an error, or simply do nothing. By testing a list of known protocol schemes, a website can build a profile of which applications are installed on the visitor's device, creating a highly distinctive fingerprint.

Privacy Impact

Protocol-based application detection is one of the most privacy-invasive fingerprinting techniques because it reveals information about the user's software environment rather than their hardware. While hardware fingerprints identify the device, application fingerprints identify the person and their activities.

The privacy implications are significant:

  • Software inventory: By testing common protocol handlers (Spotify, Discord, Telegram, WhatsApp, Steam, Epic Games, Zoom, Teams, VS Code, Sublime Text, and dozens more), a website can determine which applications are installed.
  • Behavioral profiling: Installed applications reveal interests, profession, and behavior patterns. A developer with vscode://, iterm2://, and docker:// presents a different profile from a gamer with steam://, epicgames://, and discord://.
  • Device uniqueness: The specific combination of installed applications is highly unique. Even among devices with identical hardware, the installed software set varies dramatically between users.
  • Cross-browser tracking: Protocol handlers are registered at the OS level, not the browser level. This means the same application fingerprint persists across all browsers on the device, enabling cross-browser tracking.

A landmark 2021 study by FingerprintJS demonstrated that protocol-based fingerprinting could test 32 popular applications in seconds, producing a fingerprint that uniquely identified 95% of test subjects. The technique worked across Chrome, Firefox, Edge, and other browsers. The research prompted browser vendors to begin implementing mitigations, but the fundamental vulnerability persists in many scenarios.

The technique is particularly concerning because it requires no permissions and can be performed silently. There is no notification to the user that their installed applications are being probed.

Technical Background

How Protocol Detection Works

Protocol detection exploits the browser's behavior when navigating to a URL with an unknown or registered custom scheme. Several techniques have been developed:

iframe navigation method: A website creates a hidden iframe and sets its src to a custom protocol URL (e.g., slack://open). If Slack is installed, the browser attempts to handle the navigation. If not, the iframe receives an error. The timing and behavior of this response differ based on whether the handler exists.

Popup window method: Opening a window.open() to a custom protocol URL produces different behavior depending on handler registration. On some browsers, the popup is consumed by the application handler. On others, it remains as a blank window.

Focus/blur detection: When a protocol handler launches an external application, the browser window loses focus. By monitoring blur and focus events, a website can detect whether an application was successfully launched.

Timing-based detection: The time taken for the browser to process a protocol navigation varies depending on whether a handler exists. Installed handlers produce a faster or slower response (depending on the browser) than unregistered protocols, and this timing difference is measurable.

Browser-Specific Behavior

Different browsers handle unknown protocols differently:

  • Chrome: Shows a dialog asking if the user wants to open the application (for known handlers) or does nothing / shows a minimal error (for unknown protocols). The dialog's presence and behavior can be detected programmatically.
  • Firefox: Shows its own handler dialog for registered protocols and an error page for unregistered ones. The navigation behavior reveals handler registration.
  • Safari: Has implemented mitigations that limit protocol probing, but timing-based detection still works in some scenarios.
  • Edge: Similar behavior to Chrome (Chromium-based), with additional protocol prompts.

The Flood Handler Problem

In 2021, researchers demonstrated a technique called "scheme flooding" that exploited protocol handlers to reliably fingerprint users across multiple browsers on the same device. The technique involved testing dozens of protocol schemes in rapid succession and measuring the response pattern. Because protocol handlers are OS-level registrations, the fingerprint was consistent across all browsers on the device, defeating browser-level privacy protections.

Timing Normalization Challenges

The core challenge in protocol detection is timing. When a browser processes a navigation to a custom protocol URL:

  1. It checks the OS protocol handler registry
  2. If a handler exists, it prepares to launch the application (or show a prompt)
  3. If no handler exists, it falls through to an error state

Steps 2 and 3 take different amounts of time, and this timing difference is the primary signal. Even when browsers attempt to normalize the visible behavior (showing the same UI for both cases), the underlying processing time often differs.

Installed Application Lists

Common protocols tested in fingerprinting scripts include:

  • Communication: slack://, discord://, telegram://, whatsapp://, signal://
  • Development: vscode://, sublime://, atom://, docker://
  • Gaming: steam://, epicgames://, uplay://
  • Productivity: notion://, evernote://, todoist://
  • Media: spotify://, vlc://, figma://
  • Meetings: zoommtg://, msteams://, webex://

Each additional protocol tested adds entropy to the fingerprint. Testing 30-40 protocols produces a sufficiently unique combination for reliable identification.

Common Protection Approaches and Their Limitations

VPNs and Proxy Servers

VPNs have no effect on protocol handler detection. Protocol registration is a local OS property, and detection happens entirely within the browser. Network-level privacy tools cannot modify protocol handler behavior.

Incognito and Private Browsing

Private browsing modes do not alter protocol handler registration. The same applications are installed in incognito as in a normal window, because protocol handlers are registered at the OS level, not in the browser profile.

Browser Extensions

Extensions can attempt to intercept protocol navigation:

  • Blocking iframe navigation: An extension can block all custom protocol navigations in iframes, but this breaks legitimate deep links and is easily detected because the blocking behavior itself is observable.
  • Normalizing timing: Extensions can add delays to all protocol navigations to normalize timing, but the overhead of the extension's interception is itself detectable, and the delay must be carefully calibrated to avoid breaking legitimate protocol links.
  • Disabling popups: Blocking window.open() for custom protocols prevents one detection method but breaks legitimate application launching.

Browser Mitigations

Modern browsers have implemented some protections:

  • Chrome added rate limiting for protocol handler checks
  • Safari implemented stricter same-origin policies for protocol navigation
  • Firefox added user gesture requirements for some protocol navigation methods

These mitigations reduce the effectiveness of rapid-fire protocol probing but do not eliminate the fundamental timing differences that enable detection.

BotBrowser's Engine-Level Approach

BotBrowser controls protocol handler behavior at the browser engine level, ensuring that all protocol navigation attempts produce uniform responses regardless of which applications are actually installed on the host system.

Timing Normalization

BotBrowser normalizes the timing of protocol navigation processing so that registered and unregistered protocols produce indistinguishable timing signatures. This eliminates the primary signal used in protocol-based fingerprinting:

chrome --bot-profile="/path/to/profile.enc" \
       --user-data-dir="$(mktemp -d)"

Uniform Behavioral Response

Beyond timing, BotBrowser ensures that the observable behavior (error states, focus/blur events, iframe status) is consistent for all protocol navigation attempts. The browser does not reveal whether a handler exists through any behavioral channel.

The protection does not block protocol navigation entirely. When a user or automation script explicitly follows a protocol link as part of a normal workflow, the navigation proceeds. Only the probing behavior, rapid enumeration of protocol handlers through timing and behavioral analysis, is neutralized.

Profile Integration

Protocol handler protection is part of the broader fingerprint profile. It works alongside OS identification, browser version signals, and other platform-specific behaviors to maintain a consistent identity:

chrome --bot-profile="/path/to/profile.enc" \
       --bot-noise-seed=42 \
       --proxy-server="socks5://user:pass@proxy:1080" \
       --user-data-dir="$(mktemp -d)"

No Host Environment Leaks

The key guarantee is that the host machine's installed applications do not leak through protocol handler queries. Whether the host has Slack, Steam, VS Code, or no custom applications installed, the protocol handler behavior is controlled by the profile, not the host environment.

Configuration and Usage

Basic CLI Usage

Protocol handler protection is automatic when loading a profile:

chrome --bot-profile="/path/to/profile.enc" \
       --user-data-dir="$(mktemp -d)"

Playwright Integration

const { chromium } = require('playwright-core');

(async () => {
  const browser = await chromium.launch({
    executablePath: '/path/to/botbrowser/chrome',
    args: [
      '--bot-profile=/path/to/profile.enc',
    ],
    headless: true,
  });

  const context = await browser.newContext({ viewport: null });
  const page = await context.newPage();

  await page.goto('https://example.com');
  // Protocol handler queries will produce uniform responses
  // regardless of host machine's installed applications
  await browser.close();
})();

Puppeteer Integration

const puppeteer = require('puppeteer-core');

(async () => {
  const browser = await puppeteer.launch({
    executablePath: '/path/to/botbrowser/chrome',
    args: [
      '--bot-profile=/path/to/profile.enc',
    ],
    headless: true,
    defaultViewport: null,
  });

  const page = await browser.newPage();
  await page.goto('https://example.com');
  // Protocol handler signals are controlled by the profile
  await browser.close();
})();

Combined with Application Identity Protection

For complete application-level privacy:

chrome --bot-profile="/path/to/profile.enc" \
       --bot-noise-seed=42 \
       --bot-config-timezone="Europe/London" \
       --bot-config-locale="en-GB" \
       --user-data-dir="$(mktemp -d)"

Verification

After launching BotBrowser with a profile, verify protocol handler protection:

// Test protocol handler timing consistency
async function testProtocolTiming(protocol) {
  const start = performance.now();
  const iframe = document.createElement('iframe');
  iframe.style.display = 'none';
  document.body.appendChild(iframe);

  return new Promise(resolve => {
    iframe.onload = () => {
      resolve(performance.now() - start);
      document.body.removeChild(iframe);
    };
    iframe.onerror = () => {
      resolve(performance.now() - start);
      document.body.removeChild(iframe);
    };
    iframe.src = `${protocol}://test`;
    setTimeout(() => {
      resolve(performance.now() - start);
      if (iframe.parentNode) document.body.removeChild(iframe);
    }, 500);
  });
}

// Both registered and unregistered protocols should
// produce similar timing
const timing1 = await testProtocolTiming('slack');
const timing2 = await testProtocolTiming('nonexistentprotocol12345');
console.log('Slack timing:', timing1);
console.log('Unknown protocol timing:', timing2);
console.log('Difference:', Math.abs(timing1 - timing2));

What to check:

  1. Timing differences between known and unknown protocols are minimal (within noise range)
  2. No focus/blur events are triggered by protocol probes
  3. Protocol detection test pages (like SchemeFlood.com) show uniform results
  4. The host machine's installed applications are not detectable through protocol queries

Best Practices

  1. Use complete profiles. Protocol handler protection works best as part of a comprehensive profile that controls all fingerprint surfaces consistently.

  2. Test against known detection methods. Visit protocol fingerprinting test pages to verify that your configuration does not leak installed application information.

  3. Combine with other protections. Protocol handler detection is often used alongside Canvas, WebGL, and font fingerprinting. Use a complete profile to ensure all vectors are covered.

  4. Keep profiles updated. As browsers implement new protocol handler mitigations and detection techniques evolve, updated profiles ensure continued protection.

  5. Avoid installing unnecessary applications on the host. While BotBrowser prevents protocol leaks, minimizing the host's installed application set reduces the overall attack surface.

Frequently Asked Questions

Can protocol detection identify specific application versions?

Generally no. Protocol handler detection reveals whether an application is installed, not which version. However, some applications register version-specific protocol schemes, which can narrow the version range.

Does protocol detection work on all operating systems?

The technique works on Windows, macOS, and Linux, but the specific behavior varies by OS. Windows protocol handlers are registered in the Windows Registry. macOS uses Info.plist declarations in application bundles. Linux uses .desktop files. BotBrowser normalizes behavior regardless of the host OS.

Can websites detect protocol handler protection?

If protection is applied at the JavaScript level (intercepting navigation events), the interception itself can be detected. BotBrowser applies protection at the engine level, making the normalization invisible to page scripts.

No. BotBrowser's protection targets the probing behavior used for fingerprinting, not legitimate protocol navigation. When a user or script explicitly follows a protocol link as part of a normal workflow, the navigation functions normally.

How many protocols can be tested in a fingerprinting script?

Modern fingerprinting scripts test 20-40 common protocol handlers. Each test takes approximately 100-500ms depending on the method, so a full scan can complete in 5-20 seconds. BotBrowser's timing normalization makes all tests produce indistinguishable results.

Is this the same as the "scheme flooding" attack?

Scheme flooding is one specific implementation of protocol-based fingerprinting, demonstrated in 2021. BotBrowser's protocol handler protection addresses scheme flooding and all other protocol detection methods by controlling the underlying engine-level behavior.

Do mobile browsers support protocol detection?

Yes, but with more restrictions. Mobile browsers (particularly Safari on iOS) have stricter policies around protocol handler navigation. BotBrowser profiles for mobile configurations include the appropriate protocol handling behavior for the target mobile platform.

Does registerProtocolHandler() play a role?

The navigator.registerProtocolHandler() API allows websites to register themselves as handlers for specific protocols. This is a separate concern from application-installed protocol detection. BotBrowser controls both the detection signals and the registration behavior as part of the profile.

Summary

Custom URL protocol handlers expose the user's installed application inventory, creating one of the most distinctive fingerprinting surfaces available. The technique works across browsers, survives private browsing modes, and reveals personal information about the user's activities and interests. BotBrowser controls protocol handler behavior at the browser engine level, normalizing timing and behavioral responses so that installed applications cannot be detected through protocol probing. For related protection, see navigator properties protection, font fingerprinting control, and comprehensive profile management.

#url#protocol#handler#fingerprinting#privacy#application-detection