Skip to content

About

Go implementation of the FoxIO JA4+ network fingerprint suite (JA4/S/H/L/T/X).

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

ja4plus-go

A clean, dependency-free Go library implementing the FoxIO JA4+ network fingerprint suite: JA4, JA4S, JA4H, JA4L, JA4T, JA4X and JA4SSH.

Every fingerprint is a pure function over already-parsed inputs (a ClientHello struct, a *x509.Certificate, TCP SYN fields, timing values, …), so the library is I/O-free and trivially testable. Small bounds-checked byte parsers are included for the TLS ClientHello and ServerHello. Standard library only — no third-party dependencies.

go get github.com/North-web-dev/ja4plus-go

This is the broad, standalone library for the full JA4+ suite. It is independent of North-web-dev/ja4-guard (which is a JA4/JA4H implementation tuned specifically for inbound request guarding).

What JA4+ is

JA4+ is a suite of locality-preserving a_b_c fingerprints by FoxIO, both human- and machine-readable, used for threat-hunting, malware/CDN/scanner detection and actor grouping. Each sub-fingerprint targets one protocol:

Fingerprint What it fingerprints Spec
JA4 TLS client ClientHello (version, SNI, cipher/extension counts, ALPN; sorted cipher hash; sorted extension + sigalg hash) JA4.md
JA4S TLS server ServerHello (version, extension count, ALPN, chosen cipher; extension hash) JA4S
JA4H HTTP client request (method, version, cookie/referer presence, header count, Accept-Language; header hash; cookie hashes) JA4H.md
JA4L Light distance / latency — one-way latency (µs) + observed TTL, client & server variants JA4L
JA4T TCP SYN fingerprint (window size, option kinds, MSS, window scale) JA4T
JA4X X.509 certificate (issuer/subject RDN OIDs, extension OIDs — OIDs only, never values) JA4X
JA4SSH SSH traffic sample (mode packet lengths, packet counts, bare ACK counts) JA4SSH

GREASE values (RFC 8701) are filtered everywhere the spec requires.

Verification status

Every algorithm is checked against FoxIO's own documented vectors and/or real captured traffic. No hashes are fabricated — each expected value is either quoted from the spec, reproduced from a real capture, or computed from the documented algorithm. See the *_test.go files and testdata/.

Fingerprint Status How it is verified
JA4 ✅ Verified (spec vector + independent cross-check) The three cipher/extension hash vectors quoted verbatim from JA4.md match exactly. A real curl 7.81.0 ClientHello captured on the wire (testdata/curl_clienthello.bin) parses to t13d3113h2_e8f1e7e78f70_ce5650b735ce, identical to what tls.peet.ws computes for the same client. All 6 ALPN label vectors from JA4.md match. GREASE filtering tested.
JA4S ✅ Verified (real capture + documented algorithm) A real TLS 1.3 ServerHello captured from example.com (testdata/example_serverhello.bin) → t130200_1302_234ea6891581, matching the FoxIO JA4S algorithm. FoxIO publishes no ServerHello inputs for its example hashes, so a bit-for-bit match against a published malware JA4S is not reproducible.
JA4H ✅ Verified (documented algorithm) Full a_b_c_d output matched against the FoxIO ja4h.py reference algorithm on a known request, including cookie sorting, header exclusions, HTTP/2 pseudo-header handling and Accept-Language formatting.
JA4X ✅ Verified (published vector anchor + real cert) oidToHex matches 6 known DER OID encodings. A single-CN subject hashes to 7022c563de38, which is exactly the subject hash FoxIO publishes for Async/Quasar/BitRAT (7022c563de38_7022c563de38_…). End-to-end on a real example.com certificate.
JA4T ✅ Verified (published vector) FoxIO's published Windows 11 example 64240_2-1-3-1-1-4_1460_8 reproduced from its documented SYN fields. Pure function — needs TCP SYN capture as input.
JA4L ✅ Verified (documented example) The one-way-latency math reproduces the spec diagram's 5191 for a 10382 µs round trip. Pure function — needs measured handshake timestamps + TTL.
JA4SSH ✅ Verified (published vectors) FoxIO's reverse-shell c76s76_c71s59_c0s70 and interactive c36s36_c51s80_c69s0 examples reproduced. Pure function — needs per-sample SSH packet stats.

A note on empty fields

FoxIO's published materials are internally inconsistent on how an empty hashed component renders (older docs/examples show 000000000000; the current ja4x.py would emit the SHA-256 of the empty string). This library uses the suite-wide 000000000000 sentinel for every empty hashed list (JA4 ciphers/extensions, JA4S extensions, JA4X RDNs/extensions), matching JA4's documented behaviour and FoxIO's published fingerprint examples (e.g. Sliver 000000000000_…, Qakbot …_000000000000). This is documented here so the choice is explicit, not hidden.

Usage

JA4 — TLS client

import ja4plus "github.com/North-web-dev/ja4plus-go"

ch, err := ja4plus.ParseClientHello(clientHelloBytes) // full record or bare handshake
if err != nil { /* ... */ }
fmt.Println(ja4plus.JA4(ch))     // t13d3113h2_e8f1e7e78f70_ce5650b735ce
fmt.Println(ja4plus.JA4Raw(ch))  // the "_r" form: cleartext sorted lists

// Or populate ClientHello yourself from another TLS library:
ch = &ja4plus.ClientHello{
    SupportedVersions: []uint16{0x0304},
    CipherSuites:      []uint16{0x1301, 0x1302},
    Extensions:        []uint16{0x0000, 0x0010, 0x000d},
    HasSNI:            true, ServerName: "example.com",
    ALPNProtocols:     []string{"h2"},
}

JA4S — TLS server

sh, _ := ja4plus.ParseServerHello(serverHelloBytes)
fmt.Println(ja4plus.JA4S(sh)) // t130200_1302_234ea6891581

JA4H — HTTP client

req := &ja4plus.HTTPRequest{
    Method:  "GET",
    Version: "HTTP/1.1",
    Headers: []ja4plus.Header{ // in wire order, original casing
        {"Host", "example.com"},
        {"User-Agent", "curl/7.81.0"},
        {"Accept", "*/*"},
        {"Accept-Language", "en-US,en;q=0.9"},
        {"Referer", "http://example.com"},
        {"Cookie", "b=2; a=1"},
    },
}
fmt.Println(ja4plus.JA4H(req)) // ge11cr04enus_8ddaef5d77af_1eb7c54d5283_06beefe2b477

JA4X — X.509 certificate

cert, _ := x509.ParseCertificate(der)
fmt.Println(ja4plus.JA4X(cert)) // <issuerHash>_<subjectHash>_<extHash>

// or straight from ordered OID lists:
ja4plus.JA4XFromOIDs(issuerOIDs, subjectOIDs, extensionOIDs)

JA4T — TCP SYN

fmt.Println(ja4plus.JA4T(ja4plus.TCPSYN{
    WindowSize:  64240,
    Options:     []uint8{2, 1, 3, 1, 1, 4}, // option kinds, in order
    MSS:         1460,
    WindowScale: 8,
})) // 64240_2-1-3-1-1-4_1460_8  (Windows 11)

JA4L — latency / light distance

// JA4L-S: client SYN time, server SYN-ACK time, server TTL
fmt.Println(ja4plus.JA4L(synTime, synAckTime, serverTTL)) // "<µs>_<ttl>"
// JA4L-C: server SYN-ACK time, client ACK time, client TTL
fmt.Println(ja4plus.JA4L(synAckTime, ackTime, clientTTL))
fmt.Println(ja4plus.EstimatedHopCount(42)) // 22

JA4SSH — SSH traffic sample

fmt.Println(ja4plus.JA4SSH(ja4plus.SSHSample{
    ModeClientPayloadLen: 76, ModeServerPayloadLen: 76,
    ClientPackets: 71, ServerPackets: 59,
    ClientAcks: 0, ServerAcks: 70,
})) // c76s76_c71s59_c0s70  (reverse shell)

Limitations & honesty

  • JA4, JA4S and JA4H are spoofable. They are derived from fields the remote party controls and can be deliberately altered (cipher/extension ordering is sorted away precisely because clients randomise it). Use JA4+ for grouping and threat-hunting, not for authentication.
  • JA4L, JA4T and JA4SSH require data this library cannot collect itself. JA4L needs measured handshake timestamps and the observed TTL; JA4T needs the fields of a captured TCP SYN; JA4SSH needs per-sample SSH packet statistics (FoxIO samples every 200 packets). These are provided as pure functions over those inputs — you feed them from your capture pipeline.
  • JA4TScan (the active-scan 5th field of JA4T) and DHCP/NTP fingerprints are out of scope.
  • Where a component cannot be matched bit-for-bit against a FoxIO-published fingerprint (because FoxIO does not publish the raw inputs for its examples), it is verified against the documented algorithm and/or real captures, and the status table above says so plainly.

Credits

The JA4+ fingerprinting methods were created by John Althouse / FoxIO, LLC. All specification credit belongs to FoxIO; this repository is an independent Go implementation of their public spec. See LICENSE for the full licensing picture: the Go code here is MIT, while the JA4+ methods remain FoxIO's IP (JA4 is BSD-3-Clause; the rest are patent-pending under the FoxIO License 1.1). "JA4" and "JA4+" are trademarks of FoxIO, Inc.

Support

If this library saved you time, a ⭐ on the repo is hugely appreciated — it helps others find it.

Coin Address
BTC bc1q0sfghv7yfl594gjurhyhlhdgm0dtwh4dkjha36
ETH / USDT-ERC20 / BNB-BEP20 0xB827b5a8B6c5111946c5D872933b2C23484E87dE
SOL 3ch5aHrPp3CierhiNXmqmtFH2dMHh6Gfv7a97KtLMMCh
USDT-TRC20 / TRX TUAyz7TjgJdFVD2oFHWUUTNrzzAnBRgySG
TON UQAJmYVuR3hh02etjaPKJF-h6jcpdSnq9ZIFvI64NEskS6tx

About

Go implementation of the FoxIO JA4+ network fingerprint suite (JA4/S/H/L/T/X).

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages