Passive TCP/IP fingerprinting (TTL, MSS, Window Size, TCP options ordering) gives defenders a cheap, JavaScript-independent signal about who is actually connecting.
In 2026, the highest-value use case isn't OS identification — it's inconsistency detection: catching automation that spoofs the application layer but can't shape the kernel layer.
Combine TCP fingerprints (JA4T, p0f-style signatures) with TLS (JA4) and HTTP/2 (Akamai H2) signatures. A single layer is noise; three aligned layers are a story.
Plan for false positives from NAT, mobile carrier middleboxes, and corporate egress proxies. The fingerprint is a feature, not a verdict.
For most of the 2010s, TCP/IP fingerprinting felt like a dusty technique. Everything moved to TLS, then to HTTP/2 and HTTP/3, and the bot-management market converged on JavaScript challenges and TLS-level signatures like JA3.
Three things changed:
JA3 collapsed under deduplication. Once edge vendors began publishing JA3 commonality data, the most-used hashes turned out to correspond to hundreds of millions of legitimate Chrome users. Attackers simply borrowed the most common signature. JA4, released by FoxIO in 2023, partially fixed this — and its sibling JA4T explicitly extends the idea to the TCP layer.
Residential proxy networks scaled. When the IP itself stops being a useful signal, defenders need something else that varies between a real Windows client and a Linux relay claiming to be one.
eBPF and userland TCP stacks raised the cost of spoofing, not lowered it. Attackers can rewrite headers — but doing so consistently across millions of sessions, across kernel updates, while also matching every other layer, is operationally expensive. That asymmetry is what defenders exploit.
The result: TCP/IP fingerprinting in 2026 is no longer about identifying the OS. It is about detecting clients whose layers disagree.
A passive fingerprint is built primarily from the SYN and SYN-ACK packets of the three-way handshake. The fields that matter:
| Field | What it signals | Why it's stable |
|---|---|---|
| Initial TTL | OS family (Win 128, Linux/macOS 64, BSD 255) | Kernel default, rarely tuned |
| TCP Window Size | OS, sometimes version | Hardcoded or computed from kernel consts |
| Window Scale | OS, sometimes link tuning | Kernel default |
| MSS | Often path-derived (1460 eth, ~1380 VPN) | Negotiated along the path |
| TCP Options order | OS family — the strongest single signal | Set by the kernel SYN builder |
| SACK permitted | Old/embedded devices stand out | Kernel default |
| Timestamp present | Linux yes, Windows often no | Kernel default |
The option ordering is the most underrated. Linux SYN packets typically order options as MSS, SACK-permitted, Timestamp, NOP, Window Scale. Windows orders and pads them differently. An attacker who fakes the TTL but leaves the option order untouched leaks the real OS immediately.
Tools that operationalize this:
p0f v3 — Michał Zalewski's original passive fingerprinter. The signature database is dated, but the engine and field documentation are still the clearest reference.
Zeek (formerly Bro) — conn.log carries enough context to roll your own fingerprint scoring without writing C.
JA4T / JA4TS (FoxIO) — modern hashed TCP fingerprint, designed to be paired with JA4 (TLS) and JA4H (HTTP).
Suricata — TLS fingerprinting is first-class; for TCP layer signals you'll typically combine tcp.flags, tcp.mss, and tcp.wscale rules manually.
This is the headline use case. Build a small consistency model that compares:
HTTP User-Agent claimed OS
TLS JA4 cipher set typical for that OS/browser
TCP fingerprint (JA4T or equivalent) typical for that OS
If a session arrives claiming Windows 11 / Chrome 130, advertises a JA4 consistent with Chrome on Windows, but presents a TCP fingerprint with TTL 64 and Linux-ordered options — that's a high-confidence automation signal. You don't need to identify what it is. You only need the disagreement.
The base rate matters: legitimate traffic occasionally disagrees (corporate TLS-inspecting middleboxes are the worst offenders). Treat consistency as a continuous score, not a binary, and feed it into the same risk pipeline as your velocity and behavioral signals.
Datacenter VPS endpoints almost always present Linux fingerprints (TTL 64, Linux option order) regardless of what the client claims. SOCKS5/HTTP proxy software running on a Linux relay behaves the same way: the home device may be Windows, but the proxy terminates TCP, and the SYN that reaches the destination originates on the relay.
A signup flow that sees User-Agent: Windows paired with a Linux TCP fingerprint from a residential ASN is a textbook proxy-fronted automation pattern. The right response is rarely an outright block — route to step-up auth, slow the flow, or hold the account for review. Hard blocks generate appeals; soft friction generates abandonment by attackers and tolerable cost for the rare false positive.
On the internal side, passive fingerprinting on a SPAN port or via an eBPF agent on egress gateways gives you a free, agentless inventory signal. A workstation IP that has historically emitted Windows fingerprints and suddenly starts emitting Linux ones is interesting — maybe a new VM, maybe a compromised host running a foothold, maybe an unauthorized device on the segment. Either way, it's a ticket worth opening.
Naïve deployment will hurt real users. The major sources of legitimate disagreement:
NAT and CGNAT. Most home routers don't rewrite TCP options, but some carrier-grade NAT normalizes TTL and MSS. Anomalies appear that aren't malicious.
Mobile carrier middleboxes. Several carriers in markets with heavy traffic optimization terminate and re-originate TCP at the edge. iOS users behind such carriers can look identical to Linux servers at the TCP layer.
Corporate TLS inspection. Palo Alto, Zscaler, Netskope, and similar inline decryptors generate their own SYN to the destination. Inside an enterprise, every user looks like the inspection appliance.
VPN concentrators. A user on a corporate VPN presents the concentrator's fingerprint, not the device's.
QUIC / HTTP/3. TCP fingerprinting gives you nothing for QUIC. You need analogous initial-packet analysis (JA4Q is the emerging answer).
The practical mitigation is to maintain an allowlist of known middlebox signatures — your own corporate egress, major mobile carriers, the big inline-inspection vendors — and apply the consistency-score logic with a much higher threshold for traffic from those sources.
Three viable capture points, each with tradeoffs:
| Capture point | Pros | Cons |
|---|---|---|
| Edge load balancer / CDN | Sees real client SYN, no extra infra | Only useful if the vendor exposes the fields to your rules |
| Reverse proxy (Envoy, HAProxy, etc.) | You control it; eBPF extraction works | Only useful where the proxy terminates TCP |
| Out-of-band SPAN / mirror port | No path impact | Costs a tap, scales painfully |
For storage: a fingerprint hash plus source IP and timestamp is roughly 50 bytes per session. Don't store raw packets — you almost never need them after the first hour, and PCAPs invite GDPR pain. Hash, score, forward to your SIEM.
A reasonable retention rule of thumb is the same as your authentication logs: 90 days for security investigation, longer only with a documented purpose.
Start simple. For each session, extract:
ja4t = TCP fingerprint hash
ja4 = TLS fingerprint hash
ua_os = OS parsed from User-Agent
Maintain rolling tables of which `ja4t` values appear with which `ua_os` in your own traffic. Compute:
p_consistent = P(ja4t | ua_os) * P(ja4 | ua_os)
Anything in the bottom 1% across a 7-day window is worth surfacing. Tune from there. The point is not statistical purity — it is giving your existing risk engine a feature it didn't have, with a clear privacy and operational story.
Two things to be honest about:
It is not a silver bullet. Sophisticated attackers using eBPF-based packet rewriters, custom userland TCP stacks (gVisor, custom Rust stacks), or SDK-embedded botnets routing traffic through real consumer devices can produce consistent fingerprints across all layers. TCP fingerprinting raises the cost of automation; it does not end the game.
It is not a replacement for behavioral and account-history signals. Fingerprinting tells you about a connection. Account safety is a property of the account, accumulated over its lifetime. Treat the network signal as one feature among many in your risk model.
FoxIO's JA4 specification — github.com/FoxIO-LLC/ja4 — the current reference for hashed fingerprinting across TCP, TLS, and HTTP layers.
p0f v3 documentation by Michał Zalewski — still the clearest explanation of what each field means and why.
RFC 9293 — the current TCP specification, for the field definitions themselves.
The fingerprint hash is generally treated as a technical security measure, similar to logging IP addresses. Document the purpose (fraud prevention), set a retention period, and disclose in your privacy policy. Consult counsel for your jurisdiction.
For QUIC sessions, yes — there's no TCP handshake. But QUIC's initial packets have their own quirks, and JA4 has a QUIC variant (JA4Q). The technique adapts; it does not disappear.
Yes, with effort. eBPF-based egress rewriting on a Linux host can produce a Windows-shaped SYN. The defense is consistency across layers (TCP + TLS + HTTP/2 + behavior) and watching the base rate — a rare hash that suddenly accounts for 5% of signups is suspicious regardless of what it claims.
If your traffic already flows through a CDN with bot management, enable JA4 logging and look at TCP-layer signals if exposed. If you run your own edge, deploy Zeek on a SPAN port for a week and inspect conn.log. You will be surprised how much signal is already sitting in your traffic.
We won't spam your inbox.
Comments :
Reader
May 28, 2026Finally someone explains why VPN-only stacks still leak at Layer 4.
ReplyAnti-fraud engineer
May 28, 2026Cross-signal consistency checks are underrated — UA alone is useless in 2026.
ReplyReader
May 28, 2026Hardware alignment vs. V8 patching trade-off is the clearest explanation I've read.
Reply