Repository navigation
JA4T: no text specification, and Rust diverges from Wireshark/Zeek #304
Description
Summary
The technical specification for JA4T is severely lacking in the repo -
technical_details/ contains only JA4T.png, and the only textual
definitions are a one-line table entry in technical_details/README.md, a
single example string in the root README, external blogs, and a format
comment in rust/ja4/src/tcp.rs:121-126.
Without a spec, the three implementations that do exist (Rust, Wireshark,
Zeek) have drifted apart on four edge cases. In each case Wireshark and Zeek
agree with each other and Rust differs (as at commit 0e54bc8).
More detail
1. Empty TCP options placeholder
For a SYN carrying zero TCP options:
- Rust joins an empty options vector, leaving the field empty - e.g.
64240__0_0(rust/ja4/src/tcp.rs:128-134). - Wireshark emits
00(wireshark/source/packet-ja4.c:666-680). - Zeek emits
00(zeek/ja4t/main.zeek:198-202).
2. Absent MSS and window-scale formatting
- Rust prints
unwrap_or(0)with no padding ->0
(rust/ja4/src/tcp.rs:139-140). - Wireshark and Zeek print
%02d->00(packet-ja4.c:668-677;
zeek/ja4t/main.zeek:204-210).
A SYN with no MSS and no window-scale option is 65535_00_00_00 in
Wireshark/Zeek but 65535__0_0 in Rust (combined with 1 above).
3. Duplicated MSS / window-scale options
If MSS or window-scale appears more than once in the options list:
- Rust takes the first occurrence (
rust/ja4/src/tcp.rs:76-85). - Wireshark and Zeek overwrite on each occurrence, so the last wins
(packet-ja4.c:1461-1466;zeek/ja4t/main.zeek:109-114).
(The ordered option-kind list itself is handled identically everywhere - no
implementation deduplicates it.)
4. ECN-flagged SYNs
A SYN negotiating ECN sets CWR and ECE (flags 0xC2):
- Rust detects an initial SYN via bitmask (SYN set, ACK clear), explicitly
ignoring CWR/ECE; a unit test asserts0xC2is accepted
(rust/ja4/src/tcp.rs:14-15,145-159). - Wireshark requires
tcp_flags == 0x02exactly (packet-ja4.c:1266) - an
ECN-setup SYN produces no JA4T. - Zeek requires flags equal to
TH_SYNexactly (zeek/ja4t/main.zeek:126)- skipped also.
So ECN-capable clients are fingerprinted by Rust and silently invisible to
Wireshark and Zeek.
Ask
- Publish a
technical_details/JA4T.mddefining the field layout
(window_size_options_mss_windowscale) and the canonical behavior for:
empty options, absent MSS/window-scale, duplicated options, and which TCP
flag combinations qualify as a fingerprintable SYN. - Align implementations.
Activity
vlvkobal commentedon Aug 27, 2026
1, 2, and 3 are implemented in #310.