SearchBook a call

JOURNAL / Security

Fingerprints below HTTP: how servers recognise the software that connects

How servers recognise clients by TLS ClientHello, HTTP/2 settings and header order, how defenders use it, where it fails, and what it means for agents.

Before a server reads the first line of a request, it has already received bytes the client chose without being asked: how it opens Transport Layer Security (TLS) and how it sets up HTTP/2 (version 2 of the Hypertext Transfer Protocol, HTTP). The request then adds one more choice, the order of its headers. Software libraries make those choices, not people, so they say a lot about which program is connecting and little about who is behind it. This post covers how these fingerprints work, what defenders use them for, where they break, and what they mean for artificial intelligence (AI) agents and other automation.

First principles

A server cannot see the program on the other end, only bytes. Three facts decide which bytes matter.

  1. The opening is readable by whoever terminates it. In TLS 1.3, defined in Request for Comments (RFC) 8446, everything after the server’s reply is encrypted, but the client’s first message, the ClientHello, is not. Encrypted Client Hello (ECH), published as RFC 9849, hides the real hello from observers on the network path, but the server holding the ECH key still decrypts and reads it.
  2. The protocols permit variation. TLS lets the client choose and order its cipher suites and extensions, with one fixed rule: the pre_shared_key extension goes last. HTTP/2 lets each side announce its own settings rather than negotiate them. The HTTP/2 specification itself notes that settings, flow control and prioritisation let an observer link a client’s actions (RFC 9113, section 10.8).
  3. Libraries make the choices and rarely change them. A browser, Go’s standard library, Python’s OpenSSL binding and curl each ship different defaults.

Four things follow.

  • A fingerprint identifies an implementation. It does not identify a person, and it says nothing about intent.
  • Programs built on the same library with its default settings share a fingerprint, so collisions are built in.
  • Any choice one client makes, another can copy. A fingerprint is evidence, never proof.
  • Each layer is set by different code: the TLS library, the HTTP/2 stack, the header logic and the User-Agent string. Disagreement between layers tells you more than any single value.

The TLS ClientHello

The ClientHello carries a version, a random value, a session identifier, a list of cipher suites and a list of extensions. Extensions hold most of the variation: key-exchange groups, signature algorithms, the Server Name Indication (SNI) that names the site, and the Application-Layer Protocol Negotiation (ALPN) list, such as h2 for HTTP/2.

JA3. Salesforce published JA3 in 2017, created by John Althouse, Jeff Atkinson and Josh Atkins. It joins five fields in wire order (TLS version, ciphers, extensions, elliptic curves and point formats) and hashes the string with Message Digest 5 (MD5). It drops Generate Random Extensions And Sustain Extensibility (GREASE) values, reserved placeholders that clients send at random so that servers which cannot tolerate unknown values fail early (RFC 8701). A companion, JA3S, hashes the server’s reply.

JA3 depended on extension order, and that broke. Chrome’s intent-to-ship notice of November 2022 proposed randomising extension order to stop servers depending on a fixed layout, and noted that a fixed order encourages servers to fingerprint Chrome. Fastly saw Chrome’s most common JA3 start to fall on 20 January 2023 and, with nearly 15 factorial possible orders, expected each permuted connection to have a practically unique JA3. Salesforce no longer maintains JA3 and archived its repository in 2025.

JA4. John Althouse, now at FoxIO, published the JA4 family in September 2023. A JA4 fingerprint has three parts, written a_b_c.

  • a is readable: the transport (TCP, the Transmission Control Protocol; QUIC; or Datagram TLS), the TLS version, whether SNI is present, the counts of ciphers and extensions, and the first and last characters of the first ALPN value.
  • b is a truncated Secure Hash Algorithm 256 (SHA-256) hash of the sorted cipher list.
  • c hashes the sorted extensions, without SNI and ALPN, followed by the signature algorithms in their original order.

Sorting makes JA4 indifferent to Chrome’s shuffle, and the split lets an analyst match on one part. The wider JA4+ family adds fingerprints for server replies, HTTP requests, certificates, TCP and more, under a licence that differs from JA4’s own.

The HTTP/2 connection

HTTP/2 replaced text with binary frames, and every client opens a connection with a preface the server reads once TLS is decrypted. An Akamai white paper by Ory Segal, Aharon Fridman and Elad Shuster, presented at Black Hat Europe in 2017, examined more than 10 million HTTP/2 connections and found four stable sources of difference.

  • SETTINGS. Which parameters a client sends, in what order, and with what values, such as header table size and initial window size.
  • WINDOW_UPDATE. How much the client enlarges the connection’s flow-control window, which starts at 65,535 octets. Stacks choose very different numbers.
  • PRIORITY. Some clients send priority frames for streams they never open, to build a dependency tree. Firefox did in 2017.
  • Pseudo-header order. HTTP/2 carries the method, scheme, authority and path as pseudo-headers, which must come before ordinary headers, but their order among themselves is free. In the paper, Chrome sent method, authority, scheme, path; Firefox sent method, path, authority, scheme; a Go client started with authority.

The paper proposed a compact string joining these parts, now usually called the Akamai HTTP/2 fingerprint. Its first use case was a client whose User-Agent claims a browser while its HTTP/2 behaviour belongs to something else, such as a scraping tool written in Go. It also observed that many HTTP/2 clients give users no way to change these details. Priority signalling has since changed: RFC 9113 deprecated the original scheme, and RFC 9218 added a Priority header, which gives clients one more detail on which to differ.

Headers and their order

Which headers a client sends, their order, and in HTTP/1.1 their capitalisation all come from code. HTTP/2 requires lowercase names, so casing disappears there, but order survives.

FoxIO’s JA4H fingerprint hashes the headers in the order they appear, hashes the sorted cookie names and, separately, the sorted names with their values, and records the first four characters of Accept-Language. FoxIO notes that a missing Accept-Language strongly suggests no person is at a browser. Amazon Web Services (AWS) Web Application Firewall (WAF) exposes header order as a field its rules can match.

What defenders use them for

Malware. Malware often carries a fixed TLS configuration, and its command servers answer it the same way every time. The original JA3 post listed fingerprints for Trickbot and Emotet and showed that pairing client and server fingerprints narrows detection. The abuse.ch Secure Sockets Layer (SSL) Blacklist publishes JA3 fingerprints tied to families such as AsyncRAT, Dridex and Quakbot, warning that they have not been tested against benign traffic.

Bots and credential stuffing. A common use is a consistency check. A request whose User-Agent says a mobile browser but whose connection looks like a Python script is suspect. The Open Worldwide Application Security Project (OWASP) guidance on credential stuffing names JA3, HTTP/2 fingerprints and header order as connection fingerprinting and gives that example. The same guidance calls multi-factor authentication (MFA) by far the best defence against password attacks and warns that client-side defences may be spoofed or bypassed, so fingerprints belong in a layer, not at the gate.

Interception and known clients. A 2017 study by Zakir Durumeric and colleagues detected interception of HTTP Secure (HTTPS) traffic by comparing the User-Agent with TLS behaviour at Mozilla’s Firefox update servers, popular e-commerce sites and Cloudflare. They found over ten times more interception than earlier estimates. In the other direction, Cloudflare suggests letting your own mobile app’s fingerprint through while challenging other traffic.

Population statistics. Cloudflare’s JA4 Signals compute, per fingerprint over the last hour of its traffic, figures such as the share of requests with browser user agents. A fingerprint that seldom comes from a browser stands out when it claims to be one.

Where fingerprints fail

Limit Why it happens Effect
Shared libraries Many programs use a common library or the operating system’s TLS stack unchanged Many applications share one fingerprint
Collisions across versions Browsers keep the same ciphers and extensions across many releases Versions cannot be told apart
Randomisation Chrome shuffles its extension order Order-based hashes such as JA3 stop working for Chrome
Drift TLS libraries change about once a year, per FoxIO Allowlists go stale
Intermediaries A proxy that terminates TLS sends its own hello You fingerprint the proxy, not the client
Imitation Any choice can be copied A match proves nothing

The JA3 post itself warned that a fingerprint common to an operating system’s sockets is less useful for detection, and Cloudflare notes that one mobile app often produces the same JA3 across devices and users. In the target captures behind curl_reap, a library we maintain, the Chrome 99 to 116 targets for Windows all share one JA4. Some requests have no fingerprint at all: plain HTTP has no handshake, and Cloudflare computes none for resumed TLS sessions.

Imitation is public and well documented. uTLS, a fork of Go’s TLS library, exists to mimic other clients’ hellos. Sergey Frolov and Eric Wustrow built it after analysing over 11.8 billion TLS connections and finding that many censorship-circumvention tools were easy to tell apart from the traffic they tried to resemble, even when they imitated popular browsers. Cloudflare states the defender’s view plainly: “Fingerprints can be easily spoofed, they change frequently” (JA4 Signals post).

The strongest case against relying on them

Fingerprinting rewards looking like the majority. A privacy browser, an accessibility tool, a research crawler or a small HTTP library can be challenged for nothing more than being uncommon, while a well-funded attacker copies a browser. It pushes the ecosystem towards ossification: Chrome shuffled its extensions partly to stop servers from coming to depend on its exact order. And imitation has legitimate uses that are hard to separate from abuse, the clearest being evading censorship, where looking like an ordinary browser is the point.

Defenders answer that fingerprints are cheap and passive, that they catch the many attackers who never change defaults, and that no careful system blocks on one alone. Both sides are right. A fingerprint is a good prior and a poor verdict.

What this means for automation and AI agents

An agent that fetches pages is a client like any other. It can present itself in four ways.

  1. As itself. It uses its HTTP library’s own fingerprint, a descriptive User-Agent with a contact address, and a polite request rate. Some sites will refuse it. That is the site’s decision, and the site can only make it if it can see what is connecting.
  2. As a real browser. An agent that drives an actual browser sends that browser’s own handshake, because it is that browser. Troy, a browser we build, works this way: its tabs are Chromium, and an agent attaches over the Chrome DevTools Protocol (CDP) to the session the person is signed into. The fingerprints are genuine, at whatever Chromium version Troy’s Electron release ships. So is the responsibility: the agent acts under that person’s identity.
  3. With a signature. The cleaner answer is to stop inferring identity from implementation details. The Internet Engineering Task Force (IETF) Web Bot Auth working group is standardising a way for automated clients to sign requests with HTTP Message Signatures and name, in a Signature-Agent header, where their public keys live. Cloudflare’s 2025 announcement quoted OpenAI as signing all requests from its Operator agent. Privacy Pass (RFC 9576) takes another route, with tokens that vouch for a client but cannot be linked to the interaction in which they were issued.
  4. As someone else. A library can reproduce a browser’s handshake, HTTP/2 preface and header order. curl_reap does this with its own TLS 1.3 engine, from templates captured for each target browser. That removes one signal a site uses to decide how to treat a request. Its responsible-use page sets the limits: it does not solve CAPTCHA challenges (Completely Automated Public Turing tests to tell Computers and Humans Apart), does not bypass authentication, paywalls or rate-limit bans, and is not designed or maintained to defeat dedicated anti-bot services. If a site has deployed one and is blocking you, that block is the line to respect. It also asks users to respect robots.txt, throttle and identify themselves.

The line that matters runs between blending in and getting past. Looking like a browser at the TLS layer is a grey area that turns on what you fetch and why. Defeating a control a site deployed to keep you out is not grey, and the curl_reap legal notice points out the legal exposure it carries.

What to do

If you defend a site or service:

  1. Log JA4, the HTTP/2 fingerprint and header order beside the User-Agent, and score on consistency between layers.
  2. Never block on a fingerprint alone or allowlist one permanently. Rebuild baselines after major browser releases.
  3. Compute fingerprints where TLS terminates. Behind a proxy or content delivery network, the origin sees only the proxy.
  4. Put strong controls where the stakes are: MFA on login and per-account rate limits.
  5. Give honest automation a lane: verify signed agents, and measure how often you challenge uncommon but legitimate clients.

If you build automation or agents:

  1. Check what your client actually sends, with a fingerprint echo service, before you deploy it.
  2. Identify yourself: a descriptive User-Agent, a contact address, and request signatures where sites accept them.
  3. When an agent acts for a person, run it in a real browser under that person’s identity, and keep its request rate modest.
  4. Treat a block as an answer. Do not use imitation to get past a control aimed at you.

As of 2026-10-25

Item Status Source
JA3 Not maintained by Salesforce; repository archived on 2025-05-01 salesforce/ja3
JA4 licensing JA4 under the Berkeley Software Distribution (BSD) 3-Clause licence; other JA4+ methods under the FoxIO License 1.1, which restricts selling them FoxIO
Cloudflare scale Over 15 million unique JA4 fingerprints a day, per its August 2024 post Cloudflare
Vendor support AWS WAF matches JA3 and JA4 on CloudFront and Application Load Balancers, and header order as a request component; Cloudflare offers JA3 and JA4 with Enterprise Bot Management AWS, Cloudflare
Malware lists About 96 malware-linked JA3 fingerprints on the abuse.ch SSL Blacklist abuse.ch
Encrypted Client Hello Published as RFC 9849 in March 2026 RFC Editor
Web Bot Auth Charter milestones are dated April and August 2026; the only working group draft, the protocol, is at version 00, dated 2026-09-01 IETF

What we could not verify

  • Firefox and extension order. Mozilla’s Network Security Services (NSS) library has a resolved bug adding an option to shuffle extensions, and a related bug to add Firefox preferences for it is still open. We found no release note saying Firefox enables it by default.
  • Signed-agent adoption. We found no independent count of sites that verify Web Bot Auth signatures. OpenAI’s help page on agent signing returned an error to our requests, so the Operator claim rests on Cloudflare’s quotation.
  • Current browser values. The HTTP/2 settings and pseudo-header orders from the Akamai paper are 2017 observations and may not match current browsers.

Sources

Specifications: RFC 8446, TLS 1.3, RFC 8701, GREASE, RFC 9113, HTTP/2, RFC 9218, HTTP priorities, RFC 9849, Encrypted Client Hello, RFC 9421, HTTP Message Signatures, RFC 9576, Privacy Pass architecture.

Fingerprint methods: Salesforce, JA3 and JA3S, salesforce/ja3, FoxIO, JA4+ network fingerprinting, FoxIO-LLC/ja4, JA4 technical details, JA4H technical details, Akamai, Passive Fingerprinting of HTTP/2 Clients.

Chrome’s extension shuffle: Chromium intent to ship, Fastly on Chrome’s ClientHello permutation, Mozilla bug 1789436, Mozilla bug 1816878.

Defender use: Cloudflare JA3 and JA4 fingerprints, Cloudflare JA4 Signals, AWS WAF request components, abuse.ch SSL Blacklist, OWASP Credential Stuffing Prevention, Durumeric et al., The Security Impact of HTTPS Interception.

Imitation and identity: Frolov and Wustrow, The use of TLS in Censorship Circumvention, uTLS, Cloudflare, Web Bot Auth, IETF Web Bot Auth working group, Web Bot Auth documents, HTTP Message Signatures for automated traffic.

Our projects: curl_reap, how it works, curl_reap, impersonation targets, curl_reap, responsible use, curl_reap legal notice, Troy, how it works.

← All journal entries