JA3/JA4+ TLS Fingerprinting — Identifying What’s Behind the Connection
Every TLS client announces itself before a single byte of application data is exchanged.
The cipher suites it supports, the extensions it requests, the elliptic curves it prefers
— these choices form a fingerprint that is remarkably stable across sessions and IPs.
A Python script using requests looks nothing like Chrome, even if the HTTP
headers are spoofed. Cobalt Strike’s TLS handshake is different from a real browser’s,
no matter how good the Malleable C2 profile is.
HoneyLens uses two fingerprinting standards — JA3 and JA4+ — to identify applications, libraries, and malware from their TLS handshakes. Every connection to any of our 30+ honeypot ports is fingerprinted, stored, and looked up against a database of 276,000+ known fingerprints.
What is JA3?
JA3 was created by Salesforce engineers (John Althouse, Jeff Atkinson, Josh Atkins) in 2017. It takes 5 fields from the TLS ClientHello message, joins them with commas, and hashes the result with MD5:
JA3 = MD5( TLS_Version, Cipher_Suites, Extensions, Elliptic_Curves, EC_Point_Formats ) Example: Raw: 771,4866-4867-4865-49196-49200-159-...,0-11-10-35-22-23-13-43-45-51-21,29-23-30-25-24,0-1-2 Hash: e7d705a3286e19ea42f587b344ee6865 Match: Chrome on Windows
The hash is deterministic for a given TLS implementation. Chrome always produces the same JA3 hash (per version), regardless of which website it visits. So does Metasploit. So does a Python script. This makes JA3 useful for answering: “what software made this connection?”
What is JA4+?
JA4+ is the next generation, created by FoxIO (John Althouse, the same creator of JA3). It improves on JA3 in two key ways:
- Human-readable metadata — the first part of a JA4 fingerprint tells you the protocol, TLS version, SNI presence, cipher count, extension count, and ALPN at a glance, without needing a database lookup
- Sorting before hashing — JA3 preserves the order of cipher suites as sent by the client. JA4 sorts them first. This makes JA4 more stable when clients randomize ordering (like Chrome’s TLS 1.3 cipher shuffling)
JA4 = a_b_c a = t13d1516h2 (human-readable: TCP, TLS1.3, domain SNI, 21 ciphers, 22 extensions, HTTP/2) b = 8daaf6152771 (SHA256 of sorted cipher suites, truncated to 12 chars) c = 02713d6af862 (SHA256 of sorted extensions + sig algorithms, truncated) Full: t13d1516h2_8daaf6152771_02713d6af862
JA4+ is actually a suite of fingerprinting methods, not just one:
| Method | What it fingerprints | Use case |
|---|---|---|
| JA4 | TLS ClientHello | Identify the TLS client (browser, library, malware) |
| JA4S | TLS ServerHello | Identify server-side TLS implementations |
| JA4H | HTTP headers + cookies | Identify HTTP clients (droppers, C2 callbacks) |
| JA4X | X.509 certificates | Identify certificate structure (issuer, extensions) |
| JA4T | TCP stack | OS fingerprinting from TCP window, TTL, MSS |
| JA4SSH | SSH traffic | Identify SSH implementations and tunnels |
How HoneyLens uses them
Every TLS connection to any honeypot port goes through the same pipeline:
Incoming TLS connection (any of 30+ honeypot ports)
│
├── eBPF captures raw packet data
│
▼
JA3: parse ClientHello → MD5 hash
JA4: parse ClientHello → a_b_c fingerprint
│
▼
Store in PostgreSQL (ja4_fingerprints table)
│
▼
Lookup against 276K+ fingerprint database
│
▼
Dashboard: "This IP uses Python/requests" or "This matches CobaltStrike"
The fingerprint database (from FoxIO’s official ja4+_db.json, 208MB)
maps fingerprints to known applications: browsers (Chrome, Firefox, Safari), libraries
(OpenSSL, BoringSSL, Python, Go), and malware (CobaltStrike, IcedID, Emotet, Trickbot).
When we see a fingerprint that matches CobaltStrike, the dashboard highlights it as a threat
— even if the attacker spoofed their User-Agent header.
Why this matters for honeypots
User-Agent lies, TLS doesn’t
An attacker can set their User-Agent to Mozilla/5.0 Chrome/120 in one line
of code. But their TLS fingerprint reveals the actual library making the connection:
python-requests, Go net/http, or curl. The
discrepancy between claimed and actual identity is itself a detection signal.
Correlate across IPs
The same scanner tool produces the same JA4 fingerprint regardless of which IP it
connects from. When we see t13d0000h1_... from 50 different IPs in one hour,
that’s one botnet, not 50 independent attackers. Fingerprints enable campaign
attribution without relying on IP reputation.
Detect known malware
CobaltStrike, IcedID, SocGholish, AsyncRAT — each has a known JA4/JA4S/JA4H fingerprint in the database. When traffic matches, it’s flagged immediately. Even custom C2 frameworks are detectable if they use standard TLS libraries with default configurations.
Our implementation
| Component | Details |
|---|---|
| JA3 parser | 516 lines, clean-room implementation, 112 known fingerprints hardcoded |
| JA4+ parser | 800+ lines, implements JA4, JA4S, JA4H, JA4X, JA4T |
| Reference database | 276K+ fingerprints from FoxIO ja4+_db.json (208MB), imported into PostgreSQL |
| Storage | Per-event fingerprints + per-IP aggregation, 8 indexes for fast lookup |
| Dashboard | Threat highlighting, TLS version badges, drill-down by fingerprint |
| API | 9 endpoints for lookup, search, statistics, and per-IP fingerprint history |
Licensing: what’s open and what’s not
This is important for anyone building on JA4+: not all components are equally open.
| Component | License | Commercial use? |
|---|---|---|
| JA3 / JA3S | BSD 3-Clause (Salesforce) | Yes, unrestricted |
| JA4 TLS Client | BSD 3-Clause (FoxIO) | Yes, unrestricted |
| JA4S, JA4H, JA4X, JA4T, JA4SSH | FoxIO License 1.1 | Non-commercial / internal only |
| JA4+ Database (276K fingerprints) | FoxIO License 1.1 | Non-commercial / internal only |
The FoxIO License 1.1 permits: internal business use, security research, education, and integration into open-source tools (with the FoxIO License retained). It does not permit: OEM/resale as part of a commercial product, or sublicensing under a different license (GPL, MIT, Apache, etc.).
For HoneyLens, this means: our JA4S/JA4H/JA4X implementations and the 276K fingerprint database are used under the educational and security research provisions of the FoxIO License. The core fingerprinting (JA3 + JA4 TLS client) is fully BSD-licensed and can be used anywhere without restriction. If we were to release HoneyLens as a fully open-source product under GPL or BSD, the FoxIO-licensed components would need to be removed or replaced — but JA3 + JA4 TLS client alone cover ~80% of the fingerprinting value.
Further reading
- JA3 on GitHub (Salesforce, BSD 3-Clause)
- JA4+ on GitHub (FoxIO)
- JA4+ Technical Blog (FoxIO)
- Original JA3 Paper (Salesforce Engineering)