Alterego: Cloning Real Browser TLS Identities


Background

Bot detection has moved beyond basic header spoofing. Many systems classify traffic based on low-level TLS characteristics such as cipher ordering, extension layout, ALPN, supported groups, and protocol negotiation. These traits are difficult to fake with ordinary HTTP libraries, and they often expose automation during the handshake, before any application data is exchanged.

In environments with strict bot controls, browser automation frameworks or cookie injection can succeed, but they are fragile and require upkeep. They also force the automation stack to execute complex JavaScript and maintain realistic browser state just to pass checks that aren’t always visible. The goal here is simpler: let a real browser establish trust when needed, then allow normal tools to reuse that identity without constant adaptation.

The idea is straightforward, though the details matter. Alterego runs as an HTTP proxy that learns the TLS fingerprint from the first upstream client it sees and presents that fingerprint on behalf of subsequent clients. In the highest-fidelity case, a human-operated browser clears challenges and establishes a validated session that automated tools inherit. But a browser is not a hard requirement. Preset fingerprints can work on their own, and cloning improves parity when a browser is available. The proxy doesn’t try to simulate browser behavior. It reuses the parts that actually matter at the network layer.

Alterego proxy shares the human client identity with automation clients
Figure 1: Two independent clients share a single network identity through the proxy

This tool is available as open source on GitHub: https://github.com/covertchannelblog/alterego


Intent

Alterego is a lightweight bridge for automation in fingerprinted environments. It is not designed for high-volume scraping, nor is it intended to facilitate unauthorized access. It exists to let security professionals and developers use standard tooling against systems they are authorized to test. A real browser is often the fastest way to establish trust, but it is not mandatory. Preset fingerprints work independently, and live cloning raises fidelity when conditions allow.

Fingerprint Flexibility. The proxy must be able to assume a specific browser TLS identity on demand, either from a preset or by cloning a live connection.

Seamless Session Inheritance. When a human solves a challenge, other tools must inherit that validated session without changes to the client.

Broad Compatibility. The proxy must expose a standard HTTP interface compatible with tools like curl, Burp Suite, and custom scripts.

A screenshot of Alterego's terminal interface showing a cloned Firefox fingerprint and active proxy session
Figure 2: Alterego’s terminal interface showing a cloned Firefox fingerprint and proxied requests

Tools such as curl-impersonate and curl_cffi improve the realism of automated HTTP traffic by embedding browser-like TLS and HTTP profiles into conventional clients. These approaches rely on curated, static fingerprints rather than inheriting identity from a live browser session.

Other projects take a full browser approach. For example, thermoptic routes traffic through a browser environment so requests match Chrome across TCP, TLS, and HTTP layers. This can deliver high fidelity, but it also adds complexity because each request effectively flows through a browser process.

Commercial scraping services take a different path, abstracting access behind managed APIs that handle fingerprinting, session state, and challenge flows. These systems are typically used in adversarial, large-scale settings and are not aimed at cooperative testing workflows.

Alterego sits between these options. It lets existing clients reuse the identity a live browser establishes without routing every request through a browser or depending on a fixed profile. This is often the practical middle ground when you want to keep using tools like curl or Burp Suite, but need the TLS layer to match what already passed.


Architecture

Alterego sits in front of multiple clients—typically a browser and an automation tool—and gives them a shared network identity. Both connect to the same proxy. The browser teaches the proxy what its TLS ClientHello looks like. The proxy then replays that structure for outbound connections made on behalf of other clients.

The browser handles any challenge flow the site requires. The proxy captures session cookies and authorization tokens and stores them. When the automation client makes a request, the proxy injects the stored session state so the client inherits the authenticated context. The automation client does not need to run JavaScript or solve challenges. If re-validation is required, the operator can handle it in the browser while tool traffic continues.

Sequence diagram showing Alterego learning a browser identity then applying it to automated traffic
Figure 3: The proxy learns identity from the browser, then applies it to automation traffic

TLS Fingerprint Mechanics

When a client connects over HTTPS, it doesn’t simply negotiate “TLS 1.3.” The ClientHello advertises a full shape: version preferences, cipher suite list and ordering, supported groups, key share behavior, ALPN list, extensions and their order, record sizing, and more. Modern bot systems use this shape as a strong classification signal.

Most HTTP libraries produce a ClientHello that looks nothing like Chrome or Firefox. Even if you spoof the User-Agent and behave like a browser at the application layer, a mismatched TLS stack is often enough to flag the request.

Alterego handles this using uTLS in two modes:

  • Preset browser profiles. uTLS ships curated profiles that mimic major stacks such as Chrome and Firefox, including realistic cipher ordering and extension layouts.

  • Raw ClientHello cloning. Alterego can also learn a fingerprint from a downstream client, parse it, and configure uTLS to replay that exact structure while still randomizing GREASE values. This is the default behavior. The first downstream client to connect becomes the canonical fingerprint until the process exits.

The advantage of cloning is that there is no guesswork. The proxy reuses the real ClientHello template that already worked, so the TLS layer that hits the edge matches what established trust.


Testing Against Cloudflare

Cloudflare Bot Management assigns each request a score from 1 to 99, where lower scores indicate automation and higher scores suggest human traffic. Cloudflare is both the largest player in this space and one of the easiest to test against, thanks to exposed headers and a public endpoint that reflects scoring details.

To validate Alterego, I tested against a public endpoint that echoes bot management headers. All tests ran from the same residential connection to isolate fingerprint effects from network reputation.

Baseline: Vanilla curl

$ curl -s https://request-cf.coyotelabs.us | jq '{score: .botManagement.score, ja4: .botManagement.ja4, detectionIds: .botManagement.detectionIds}'
{
  "score": 1,
  "ja4": "t13d3112h2_e8f1e7e78f70_b26ce05bbdd6",
  "detectionIds": [33563831, 159600225, 33554817]
}

Cloudflare classifies this as automated. In testing, the presence of detection IDs consistently correlated with a score of 1.

User-Agent Spoofing

$ curl -s https://request-cf.coyotelabs.us \
  -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0" \
  | jq '{score: .botManagement.score, detectionIds: .botManagement.detectionIds}'
{
  "score": 1,
  "detectionIds": [159600225, 33563831]
}

The score remains 1. One detection ID disappears. Given that the only change here is the User-Agent header, it is reasonable to infer that the missing ID is probably tied to a User-Agent heuristic. The TLS fingerprint still does not resemble a browser.

Alterego with Randomized Profile

Routing through Alterego with a randomized uTLS profile:

# Without ALPN
$ curl -s https://request-cf.coyotelabs.us --proxy http://127.0.0.1:8888 -k \
  | jq '{score: .botManagement.score, ja4: .botManagement.ja4}'
{
  "score": 64,
  "ja4": "t12d200900_b7c2b9fabcd6_7b8f832a3d3f"
}

The score jumps to 64 and detection IDs disappear. The 00 segment in the JA4 hash indicates that ALPN was not negotiated, which is not consistent with modern browsers.

### With ALPN enabled
{
  "score": 84,
  "ja4": "t12d1709h2_c86391664905_e62f36b0334b"
}

With ALPN enabled, the score reaches 84. The h2 marker reflects HTTP/2 support, which aligns more closely with browser traffic.

uTLS Browser Preset

Using the HelloFirefox_Auto preset with a matching User-Agent:

$ curl -s https://request-cf.coyotelabs.us --proxy http://127.0.0.1:8888 -k \
  -H "User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0" \
  | jq '{score: .botManagement.score}'
{
  "score": 95
}

The curated preset enforces the extension order and GREASE behavior Cloudflare expects from Firefox-like traffic, bringing the score close to parity.

Full Browser Identity Cloning

Cloning the exact fingerprint from a real Firefox session:

$ curl -s https://request-cf.coyotelabs.us --proxy http://127.0.0.1:8888 -k \
  | jq '{score: .botManagement.score}'
{
  "score": 99
}

This reaches the top of Cloudflare’s published scale. Based on observable metrics such as JA4, the proxied request matches what Firefox produced directly.

Summary

Method Score
Vanilla curl 1
User-Agent spoofing 1
Randomized TLS (no ALPN) 64
Randomized TLS (with ALPN) 84
uTLS Firefox preset 95
Cloned browser fingerprint 99

User-Agent spoofing alone is ineffective. Randomized profiles help but still leak tells. Curated presets get very close. Cloning a real browser can reach parity.

Caveats: Scores vary between runs. Network reputation also matters. Fingerprint quality sets the ceiling, but other factors influence the final score.


Limitations & Technical Constraints

Alterego supports preset-only operation and live cloning. The highest-fidelity workflow uses a real browser to establish trust, but the proxy does not depend on a browser to function. If a target continuously validates every request rather than accepting session state as durable proof, the benefit of identity sharing decreases.

The downstream interface is HTTP/1.1, so browser-specific HTTP/2 framing parameters are not cloned. Upstream traffic uses Go’s standard HTTP/2 transport. This creates a mismatch between a browser-like TLS handshake and Go-style HTTP/2 frames. In practice, many current defenses weight TLS more heavily than HTTP/2 framing.

Throughput remains bounded by plausible activity for a single identity. Fingerprint parity does not override rate limits or frequency-based heuristics.


Future Work

Alterego reduces TLS fingerprinting as a detection signal, but detection systems continue to evolve. Areas worth further work include:

HTTP/2 Frame Impersonation. Matching browser-specific HTTP/2 framing would close the remaining passive network gap.

Identity Pooling & Location Awareness. Managing multiple browser-backed identities across networks could improve throughput while keeping each identity grounded in a real session.

Expanded System Analysis. Cloudflare is the most visible proving ground, but testing against Akamai, DataDome, Kasada, and Imperva would likely surface different signal weightings and edge cases.