How OmniRoute's TLS Stealth and HTTP Fingerprinting Bypass AI Provider Blocking

OmniRoute defeats IP, TLS, and browser fingerprinting filters used by AI providers like Claude-Web, Perplexity, and Grok through two complementary techniques: custom TLS fingerprint transport that mimics real browser handshakes, and a stealth browser pool that generates authentic HTTP headers and handles cookie challenges.

AI providers increasingly deploy multi-layered blocking systems to detect and reject automated API traffic. OmniRoute, an open-source routing layer for LLM requests, implements sophisticated countermeasures that make automated requests indistinguishable from genuine browser sessions. This article examines the two core mechanisms—TLS fingerprinting and HTTP fingerprinting via stealth browsers—and how they're implemented in the codebase.

TLS Stealth: Fingerprinting the TLS Handshake

Many AI providers protected by Cloudflare Enterprise or similar WAFs analyze the TLS ClientHello message—the very first packet in a TLS handshake—to fingerprint clients. Differences in cipher suite ordering, supported extensions, or SNI formatting can flag a request as originating from automation tools versus a real browser.

How TLS Fingerprint Transport Works

In open-sse/utils/proxyFetch.ts, OmniRoute implements a conditional TLS fingerprinting layer that activates only when needed:

  • Provider allow-listing: The function tlsFingerprintProviderAllowed() checks if the target provider appears in TLS_FINGERPRINT_PROVIDERS
  • Context isolation: The actual fetch executes inside tlsFingerprintContext.run(), an AsyncLocalStorage wrapper that tracks whether fingerprinting was used
  • Result transparency: The wrapper returns { result, tlsFingerprintUsed } so upstream code can observe the bypass status
// From open-sse/utils/proxyFetch.ts (lines 82-121)
interface ProxyFetchOptions {
  provider: string;
  proxied: boolean;
}

async function proxyFetch(
  url: string,
  init: RequestInit,
  options: ProxyFetchOptions
): Promise<{ result: Response; tlsFingerprintUsed: boolean }> {
  const store = { used: false };
  
  if (tlsFingerprintProviderAllowed(options.provider, options.proxied)) {
    return tlsFingerprintContext.run(store, async () => {
      const result = await executeTlsFingerprintedFetch(url, init);
      store.used = true;
      return { result, tlsFingerprintUsed: true };
    });
  }
  
  // Standard fetch path for non-targeted providers
  const result = await fetch(url, init);
  return { result, tlsFingerprintUsed: false };
}

The TLS fingerprint client constructs a tls.ClientHello that byte-matches Chrome or Edge's handshake. This includes:

  • Exact cipher suite list ordering
  • TLS extension sequence and padding
  • SNI formatting that matches browser behavior
  • ALPN protocols advertised identically to real browsers

Feature Flag Configuration

TLS fingerprinting is controlled through environment variables defined in src/shared/constants/featureFlagDefinitions.ts at line 112:

export ENABLE_TLS_FINGERPRINT=true
export TLS_FINGERPRINT_PROVIDERS="codex,groq,claude-web"

This opt-in design ensures only providers that actually enforce TLS fingerprinting incur the performance overhead of custom TLS negotiation.

Error Handling for Security

When fingerprinted TLS fails, OmniRoute surfaces a deterministic error without retry variants. The TLS_FINGERPRINT_FAILED error type (defined in the codebase and tested in tests/unit/tls-proxy-context.test.ts) prevents replay attacks by refusing to automatically attempt alternative fingerprints that could reveal automation patterns.

HTTP Fingerprinting: The Stealth Browser Pool

TLS fingerprinting alone cannot defeat HTTP header fingerprinting or cookie challenges. Providers like Claude-Web, Perplexity, and Pollinations image generation require actual browser cookies and realistic header sets including Sec-CH-UA, Accept-Language, and proper User-Agent strings with platform hints.

Browser Pool Architecture

The open-sse/services/browserPool.ts implementation maintains a shared pool of headless Chromium instances with the puppeteer-stealth plugin injected. Key characteristics:

  • Persistence: Browsers persist across requests to amortize launch cost
  • Cookie state: Each browser context maintains a real cookie jar
  • Stealth detection: The stealthAvailable flag (lines 402-410) tracks whether state.cloakLaunch !== null
// From open-sse/services/browserPool.ts (lines 402-410)
interface BrowserPoolState {
  cloakLaunch: Browser | null;  // The stealth browser instance
  contexts: Map<string, BrowserContext>;
}

function isStealthAvailable(state: BrowserPoolState): boolean {
  return state.cloakLaunch !== null && 
         !state.cloakLaunch.isConnected() === false;
}

For web-cookie providers, open-sse/services/browserBackedChat.ts invokes refreshCookiesViaBrowser() (lines 635-645) to perform a full browser session:

// From open-sse/services/browserBackedChat.ts (lines 635-645)
async function refreshCookiesViaBrowser(
  providerKey: string,
  challengeUrl: string
): Promise<CookieJar> {
  const browser = await getStealthBrowser({ poolKey: providerKey });
  const page = await browser.newPage();
  
  // Navigate through provider's cookie challenge (Cloudflare turnstile, etc.)
  await page.goto(challengeUrl, { waitUntil: "networkidle2" });
  
  // Extract cookies from the authenticated session
  const cookies = await page.cookies();
  return CookieJar.fromPuppeteerCookies(cookies);
}

The resulting HTTP request carries headers generated by actual Chromium, not synthetic values, making detection nearly impossible.

Observability via MCP Tools

Operators can inspect pool status through the browser_pool_status MCP tool in open-sse/mcp-server/tools/poolTools.ts (lines 147-200):

// Tool definition exposing stealth pool metrics
{
  name: "browser_pool_status",
  description: "Inspect browser pool health and stealth availability",
  handler: async () => {
    const pool = getGlobalBrowserPool();
    return {
      stealthEnabled: pool.config.useStealth,
      stealthAvailable: pool.isStealthAvailable(),
      activeContexts: pool.contexts.size,
      lastHealthCheck: pool.lastHealthCheck
    };
  }
}

How the Bypass Defeats Provider Blocking

Blocking Layer Provider Example OmniRoute Countermeasure
IP reputation + TLS fingerprint Cloudflare Enterprise on Groq Custom tls.ClientHello matching browser cipher suites and extensions
HTTP header fingerprint Perplexity API Real Chromium headers via puppeteer-stealth
Cookie/JS challenge Claude-Web, Claude-API Full browser automation with persistent cookie jar
Behavioral bot detection Pollinations image generation Reused browser contexts mimicking returning user sessions

The layered architecture matters: TLS fingerprinting handles transport-level blocks, while the stealth browser pool handles application-level challenges. Requests that pass both layers appear as indistinguishable from organic user traffic.

Summary

  • TLS fingerprint transport in open-sse/utils/proxyFetch.ts creates byte-identical browser handshakes for providers in TLS_FINGERPRINT_PROVIDERS
  • Stealth browser pool in open-sse/services/browserPool.ts maintains persistent, fingerprinted Chromium instances for cookie-dependent providers
  • Feature flags in src/shared/constants/featureFlagDefinitions.ts enable per-provider opt-in to minimize overhead
  • Deterministic error handling prevents retry patterns that could leak automation detection
  • MCP observability tools allow runtime verification of bypass effectiveness

Frequently Asked Questions

What providers does OmniRoute's TLS stealth support?

OmniRoute supports any provider listed in the TLS_FINGERPRINT_PROVIDERS environment variable. The codebase explicitly tests against Codex, Groq, Claude-Web, Perplexity, and Pollinations. The allow-list design means you can enable fingerprinting only for providers that actually require it, keeping direct fetches fast for permissive APIs.

Does TLS fingerprinting work without a proxy?

No. The tlsFingerprintProviderAllowed() function checks both the provider allow-list and whether the request is routed through a proxy (proxied: true). The TLS fingerprint client is designed for proxy transit scenarios where the upstream provider would otherwise see the proxy's default TLS signature. Direct connections from OmniRoute use standard library TLS.

How does stealth browser pooling affect performance?

The pool amortizes browser launch cost across multiple requests. According to browserPool.ts, a single stealth browser instance serves sequential requests for the same provider key, and browserBackedChat.ts caches cookie jars to avoid redundant challenge navigation. First-request latency increases by 2-4 seconds for browser launch, but subsequent requests typically add under 200ms versus direct API calls.

Can providers detect the stealth browser as headless Chrome?

The puppeteer-stealth plugin patches known headless detection vectors: navigator.webdriver, navigator.plugins length, Chrome runtime properties, and WebGL renderer strings. The test suite in tests/unit/notion-web-models-discovery.test.ts validates that fingerprinted headers pass common detection libraries. However, advanced providers may employ behavioral analysis (mouse movement, scroll patterns) that pure API traffic cannot replicate—OmniRoute handles the network layer only.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →