How OmniRoute's TLS Stealth Fingerprinting Works to Avoid AI Detection

OmniRoute avoids AI provider detection by routing requests through a native TLS client that crafts browser-identical ClientHello handshakes, making traffic indistinguishable from genuine Chrome or Edge browsers.

OmniRoute is an open-source AI routing proxy that masks its identity using TLS stealth fingerprinting. When enabled, it replaces Node.js's distinctive TLS signature with a custom-built handshake that mimics real browser fingerprints. This technique bypasses Cloudflare challenges, bot detectors, and AI-provider rate limits that filter based on JA3 hashes and TLS metadata.

How TLS Fingerprint Detection Blocks AI Proxies

AI providers and CDN services like Cloudflare analyze the ClientHello message sent during TLS negotiation. Standard Node.js applications emit a unique combination of:

  • TLS version and cipher suites
  • Extension order and supported curves
  • JA3 fingerprint hash

These signatures are cataloged by security vendors. When OmniRoute sends a vanilla Node.js fetch, detection systems immediately flag it as automated traffic.

OmniRoute's Stealth Architecture

The stealth system operates through six coordinated components controlled by feature flags and provider allow-lists.

1. Feature Flag Activation

Stealth mode is gated by ENABLE_TLS_FINGERPRINT, defined in src/shared/constants/featureFlagDefinitions.ts. The flag must be explicitly set to "true"—it defaults off to preserve normal operation.


# Enable TLS stealth globally

export ENABLE_TLS_FINGERPRINT=true

2. Provider Targeting with TLS_FINGERPRINT_PROVIDERS

Not all providers require stealth. OmniRoute uses TLS_FINGERPRINT_PROVIDERS to filter which upstream services receive masked traffic:


# Comma-separated list of providers to fingerprint

export TLS_FINGERPRINT_PROVIDERS="claude,grok,perplexity,codex"

This allow-list ensures stealth resources are only spent where detection risk exists.

3. Native TLS Client Singleton (tlsClient.ts)

The core stealth logic lives in open-sse/utils/tlsClient.ts. This file exports a global TlsClient instance that wraps the tls-client-node binary.

Key responsibilities:

  • Binary lifecycle: Downloads and caches the native executable on first use
  • Circuit-breaker pattern: Tracks failure rates and temporarily disables stealth if errors exceed threshold
  • API compatibility: Exposes tlsClient.fetch(url, options) matching standard fetch semantics
// From open-sse/utils/tlsClient.ts
const tlsClient = new TlsClient();
export const tlsFetch = tlsClient.fetch.bind(tlsClient);

When ENABLE_TLS_FINGERPRINT === "true", the singleton initializes buildNativeTlsClientOptions() from open-sse/services/tlsClientDownloadDir.ts to configure the binary.

4. Binary Management (tlsClientDownloadDir.ts)

open-sse/services/tlsClientDownloadDir.ts handles platform detection and binary provisioning:

  • Detects OS/architecture (Linux x64, macOS ARM64, etc.)
  • Downloads pre-compiled tls-client-node release if absent
  • Writes to deterministic cache directory for reuse
  • Exposes buildNativeTlsClientOptions() with profile names, proxy URLs, and timeouts

This separation keeps the main codebase portable while delegating low-level TLS crafting to a specialized native tool.

5. Provider-Specific Wrappers

Each stealth-enabled provider has a dedicated wrapper in open-sse/services/. Examples include:

Provider File Path Profile Constant
Claude claudeTlsClient.ts CLAUDE_PROFILE
Grok grokTlsClient.ts GROK_PROFILE
Perplexity perplexityTlsClient.ts PERPLEXITY_PROFILE
ChatGPT chatgptTlsClient.ts CHATGPT_PROFILE

These wrappers import tlsClient.fetch and bind it to provider-specific configurations:

// Simplified from claudeTlsClient.ts
import { tlsFetch } from "../utils/tlsClient";

export function tlsFetchClaude(url: string, options: RequestInit) {
  return tlsFetch(url, {
    ...options,
    tlsProfile: "chrome_120", // JA3 fingerprint matching Chrome 120
    // Additional Claude-specific headers and behavior
  });
}

Internal executor code (executors/claude-web/transport.ts) then calls tlsFetchClaude instead of native fetch.

6. Fallback and Resilience

open-sse/utils/proxyFetch.ts coordinates the decision logic. If any of the following occur:

  • ENABLE_TLS_FINGERPRINT is disabled
  • Provider not in TLS_FINGERPRINT_PROVIDERS
  • Binary download fails
  • Circuit-breaker is open (too many recent failures)

…the request automatically falls back to standard Node.js fetch. This graceful degradation ensures service continuity even when stealth is unavailable.

Complete Configuration Example

// Environment setup (equivalent to .env file)
process.env.ENABLE_TLS_FINGERPRINT = "true";
process.env.TLS_FINGERPRINT_PROVIDERS = "claude,grok,perplexity";
// Optional: route binary through corporate proxy
process.env.TLS_CLIENT_PROXY = "http://proxy.example.com:8080";

// Application code
import { tlsFetchClaude } from "open-sse/services/claudeTlsClient";

async function stealthQuery(prompt: string) {
  const response = await tlsFetchClaude(
    "https://claude.ai/api/organizations/[org]/completion",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        prompt,
        model: "claude-3-opus-20240229",
        max_tokens: 4096,
      }),
    }
  );

  return response.json();
}

When executed, this produces a TLS handshake identical to Chrome 120: same JA3 hash, extension order, cipher suite preferences, and SNI behavior. Detection infrastructure classifies OmniRoute as legitimate browser traffic.

Circuit-Breaker and Operational Safety

The TlsClient class implements a failure threshold circuit breaker:

  • Successive native binary failures increment an internal counter
  • After threshold (configurable, default 5 failures in 60 seconds), circuit opens
  • Open circuit blocks stealth attempts for backoff period (default 30 seconds)
  • Requests during open circuit use standard fetch fallback

This prevents cascading failures from repeatedly spawning a misconfigured or corrupted binary.

Inbound TLS Capture (tlsCapture.ts)

For OmniRoute's TPROXY transparent proxy mode, src/mitm/tproxy/tlsCapture.ts provides isTlsClientHello() to detect TLS handshakes on raw socket streams. This enables:

  • TLS termination when OmniRoute sits inline between client and upstream
  • Extraction of SNI for routing decisions
  • Optional re-encryption with stealth fingerprint on outbound leg

This completes the full proxy pipeline: inbound traffic captured, optionally inspected, then re-emitted with browser-mimicking TLS signatures.

Summary

  • OmniRoute's TLS stealth fingerprinting masks Node.js origins by substituting native fetch with a custom binary that crafts browser-identical ClientHello messages.
  • Feature flags (ENABLE_TLS_FINGERPRINT, TLS_FINGERPRINT_PROVIDERS) provide granular, runtime control over which providers receive stealth treatment.
  • Architecture components: flag definitions, singleton client, binary downloader, provider wrappers, circuit-breaker, and fallback logic work together in open-sse/utils/tlsClient.ts and related files.
  • Resilience mechanisms include automatic fallback to standard fetch and circuit-breaker protection against binary failures.
  • Result: AI providers see standard browser fingerprints, bypassing JA3-based bot detection and Cloudflare interstitial challenges.

Frequently Asked Questions

What is a JA3 fingerprint and why does it matter for AI detection?

A JA3 fingerprint is an MD5 hash derived from TLS ClientHello fields including version, cipher suites, and extensions. Security systems maintain allow-lists of "good" browser JA3 signatures and block outliers. Node.js emits a distinctive JA3 that rarely matches browsers, making automated traffic trivial to identify and throttle. OmniRoute's native binary generates JA3 hashes identical to Chrome or Edge, eliminating this detection vector.

Can I use TLS stealth fingerprinting without downloading external binaries?

No. The tls-client-node binary is required for stealth operation. The implementation in open-sse/services/tlsClientDownloadDir.ts automatically handles download and caching on first use. If the binary cannot be retrieved (air-gapped environments, restricted networks), OmniRoute falls back to standard Node.js fetch without stealth—functionality is preserved but detection risk increases.

How do I verify that TLS stealth is actually active for my requests?

Check runtime logs at DEBUG=omni:tls level. When stealth is engaged, you'll see entries referencing tls-client-node spawn, profile selection (e.g., chrome_120), and successful JA3 negotiation. Silent fallback to native fetch indicates stealth was bypassed—verify ENABLE_TLS_FINGERPRINT="true", provider is in TLS_FINGERPRINT_PROVIDERS, and binary exists in the cache directory returned by tlsClientDownloadDir.ts.

Does TLS stealth fingerprinting impact request latency?

Yes, with modest overhead. The native binary spawn adds 10-50ms per cold-start request; subsequent requests reuse the process pool. Circuit-breaker state and proxy chaining (tlsClientProxy.ts) add minimal latency. For high-throughput scenarios, monitor open-sse/utils/tlsClient.ts metrics and tune connection pooling—native client maintains persistent TLS sessions where possible.

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 →