Learn how to use JA4 network fingerprinting in Zeek to identify client and server software, detect malware, and track behavior across encrypted connections without requiring decryption.
Network fingerprinting helps identify client and server software without decrypting traffic or relying on IP addresses that rotate constantly. JA4, a family of fingerprinting methods released by FoxIO, expands on lessons learned from JA3 to cover not just TLS but also TCP, HTTP, SSH, and DHCP connections.
For Zeek users, JA4 is available as a maintained package that integrates directly into Zeek’s logging pipeline. This means JA4 fingerprints appear alongside familiar connection, SSL, HTTP, and SSH logs without requiring workflow changes or decryption. JA4 is useful for traffic analysis, threat hunting, and behavioral detection – tracking how software behaves rather than where it connects.
JA4 (TLS client fingerprinting) is released under BSD 3-Clause license, while other JA4+ methods (JA4S, JA4H, JA4L, JA4T, JA4SSH, JA4X) use the FoxIO License. Technical details for the algorithms can be found on the FoxIO blog.
This post covers:
- Installing the JA4 package via
zkg - Understanding JA4, JA4S, JA4H, JA4L, JA4T, JA4TS, JA4SSH, and JA4D fingerprints
- Which logs get new JA4 fields (
conn.log,ssl.log,http.log,ja4ssh.log,ja4d.log) - Practical use cases for each fingerprint type
Package Installation
The examples below use a Podman container running the official Zeek image. To start, we run a container and install the JA4 Zeek package using zkg:
$ podman run -Pit --rm --entrypoint=/bin/bash zeek/zeek:latest root@3a6f7e74ed8a:/# zkg install zeek/foxio/ja4 The following packages will be INSTALLED: zeek/foxio/ja4 (v0.18.8) Proceed? [Y/n] y Installing "zeek/foxio/ja4". Installed "zeek/foxio/ja4" (v0.18.8) Loaded "zeek/foxio/ja4"
With the package installed, we can verify it by running Zeek against one of the test PCAPs included in the JA4 repository. The goal is to confirm that the package installed correctly and that new JA4-related fields appear in Zeek’s logs.
First, create a temporary working directory for the output logs:
root@3a6f7e74ed8a:/# mkdir -p /tmp/logs
root@3a6f7e74ed8a:/# cd /tmp/logs
Next, run Zeek against the sample TLS handshake PCAP. The ja4 argument here ensures the JA4 scripts are loaded explicitly for this run:
root@3a6f7e74ed8a:/tmp/logs# zeek -C -r "$(dirname "$(zkg info ja4 | grep clones | cut -d: -f2 | tr -d ' ')")"/pcap/tls-handshake.pcapng local ja4 root@3a6f7e74ed8a:/#
After processing the PCAP, Zeek produces the usual set of logs:
root@3a6f7e74ed8a:/tmp/logs# ls -l total 112 -rw-r--r-- 1 root root 277 Jan 26 19:47 capture_loss.log -rw-r--r-- 1 root root 13497 Jan 26 19:47 conn.log -rw-r--r-- 1 root root 38707 Jan 26 19:47 loaded_scripts.log -rw-r--r-- 1 root root 780 Jan 26 19:47 notice.log -rw-r--r-- 1 root root 278 Jan 26 19:47 packet_filter.log -rw-r--r-- 1 root root 3375 Jan 26 19:47 quic.log -rw-r--r-- 1 root root 4863 Jan 26 19:47 ssl.log -rw-r--r-- 1 root root 828 Jan 26 19:47 stats.log -rw-r--r-- 1 root root 27506 Jan 26 19:47 telemetry.log
To confirm that the JA4 package is active, inspect the log headers for newly added fields. In this case, conn.log and ssl.log now include multiple JA4-related columns:
root@3a6f7e74ed8a:/tmp/logs# head -n 7 conn.log ssl.log | grep '#fields' | sed 's/\t\t*/\n/g' | grep ja4 ja4l ja4ls ja4t ja4ts ja4 ja4s
Finally, spot-check a few values from ssl.log to verify that JA4 and JA4S fingerprints are being populated as expected:
root@3a6f7e74ed8a:/tmp/logs# zeek-cut ja4 ja4s < ssl.log | sort -u q13d0310h3_55b375c5d22e_cd85d2d88918 q130200_1301_234ea6891581 q13d0310h3_55b375c5d22e_cd85d2d88918 q130200_1301_a56c5b993250
At this point, the package is installed and working. New JA4 fields are present in both conn.log and ssl.log. Depending on your site policy (local.zeek), the JA4 package may be loaded automatically after installation, or you may need to add an explicit @load ja4 directive.
ssl.log: JA4 and JA4S
When the JA4 package is loaded, ssl.log gains two new fields:
ja4ja4s
These correspond to the TLS client and server fingerprints derived from the TLS handshake. Both are computed from data exchanged in the clear before encryption is established.
ja4: TLS client fingerprint
The ja4 field fingerprints the TLS client based on the ClientHello message. It captures how the client presents itself during the handshake: protocol usage, TLS version, cipher preferences, extensions, and ALPN. ja4 is most useful for identifying:
- The TLS library or runtime in use (OpenSSL, Go TLS, Windows SChannel, etc.)
- Non-browser clients masquerading as browsers
- Malware frameworks and tooling that reuse common TLS stacks
- Sudden changes in client behavior within otherwise stable environments
Unlike JA3, the JA4 fingerprint is designed to remain stable even when clients randomize extension ordering, making it a reliable pivot point.
The ja4 field value itself encodes the transport protocol (TCP vs. QUIC), negotiated TLS version, SNI presence, counts of cipher suites and extensions, the first ALPN value, and truncated SHA-256 hashes of the offered cipher suites, extensions, and signature algorithms.

Figure 1: JA4 TLS client fingerprint structure. Image courtesy of the FoxIO JA4 GitHub repository.
ja4s: TLS server fingerprint
The ja4s field fingerprints the TLS server based on the ServerHello response. This reflects how the server selects ciphers and extensions in response to a given ClientHello.
A key property of ja4s is that it reflects how a server responds to a given ClientHello, not just the server’s standalone configuration:
- The same server may emit different
ja4svalues when responding to different clients - The same client will consistently elicit the same
ja4sfrom a given server
ja4s is valuable when paired with ja4. Together, they describe both sides of a complete TLS negotiation. Use cases include:
- Identifying specific server implementations behind CDNs or load balancers
- Detecting malicious or unusual TLS endpoints
- Spotting beaconing behavior where a client repeatedly negotiates identical TLS sessions
- Differentiating infrastructure that looks identical at the IP or domain level
ja4s is often more actionable than ja4 on its own. Pivoting on repeated ja4s values can quickly surface shared backend infrastructure, even when IPs, domains, or certificates rotate. The ja4s value captures the negotiated protocol and TLS version, the selected cipher suite, server extensions and ALPN, and a hash of the ServerHello extensions.

Figure 2: JA4S TLS server fingerprint structure. Image courtesy of the FoxIO JA4 GitHub repository.
conn.log: JA4L, JA4LS, JA4T, and JA4TS
In addition to TLS fingerprints, the JA4 package extends conn.log with several fields derived from TCP and packet timing behavior. These fingerprints are computed independently of encryption and apply to all TCP traffic, including non-TLS connections.
The following JA4-related fields appear in conn.log:
ja4l— client-to-server latency measurementja4ls— server-to-client latency measurementja4t— TCP client fingerprintja4ts— TCP server response fingerprint
Together, these fields describe how a connection behaves on the wire, not just how it negotiates TLS.
ja4l and ja4ls: light distance/location latency fingerprinting
The ja4l field captures a passive latency measurement from the client to the server, derived from the timing of the initial packets in the connection setup. This value reflects physical and network distance rather than application behavior. ja4l is useful for:
- Estimating client proximity to the sensor, server, or tap
- Detecting sudden geographic or network-path changes
- Identifying impossible or suspicious shifts in connection origin
- Supporting session hijacking or proxy detection when combined with other fingerprints
The ja4ls field is the inverse measurement: latency from the server back to the client. While often similar to ja4l, asymmetry between the two values can reveal meaningful network characteristics. Uses include:
- Identifying asymmetric routing
- Detecting load balancers, relays, or tunneling infrastructure
- Differentiating cloud-hosted services from on-prem systems
- Strengthening location-based analysis when combined with
ja4l
Together, ja4l and ja4ls provide a coarse but stable signal about network distance that does not de pend on IP reputation or geolocation databases. Because they rely on low-level packet timing, ja4l and ja4ls works on encrypted and unencrypted traffic alike.

Figure 3: JA4L fingerprint structure. Image courtesy of the FoxIO JA4 GitHub repository.
ja4t and ja4ts: TCP connection fingerprinting
The ja4t field fingerprints the TCP client based on parameters in the initial SYN packet. This includes window size, TCP options, MSS, and other characteristics determined by the client’s operating system and network stack. ja4t facilitates:
- OS, device family, and networking stack identification
- Detection of VPNs, tunnels, and proxies via MSS changes
- Differentiating servers behind load balancers or proxies
- Detecting shared backend infrastructure
- Grouping of scanners and automated tools across IP space
- Stable pivoting when IP addresses rotate frequently
The ja4ts field complements ja4t as it fingerprints the TCP server based on the SYN-ACK response. Like ja4s for TLS, ja4ts is response-dependent: the same server may produce different ja4ts values when responding to different client SYN packets, but will consistently respond the same way to identical client behavior. Together, these fields provide more analytical value than either field alone.

Figure 4: JA4T/S fingerprint structure. Image courtesy of the FoxIO JA4 GitHub repository.
http.log: JA4H
The JA4 package adds the ja4h field to http.log. Unlike TLS and TCP fingerprints, JA4H operates at the HTTP request level, fingerprinting how a client constructs its HTTP requests rather than how it negotiates a connection. JA4H requires visibility into HTTP headers, making it most useful in environments where:
- TLS is terminated upstream (reverse proxies, load balancers, WAFs)
- Plaintext HTTP is still in use
- Zeek is deployed behind a proxy or inspection point
ja4h: HTTP client fingerprint
The ja4h value fingerprints the HTTP client based on request metadata such as method, header pres ence and ordering, and cookie structure. It is designed to remain stable across requests made by the same client software, even as URLs, IPs, or user-agent strings change. ja4h is useful for:
- Differentiating browsers from scripts and bots
- Identifying automation frameworks that spoof User-Agent strings
- Grouping traffic generated by the same tool or malware family
- Detecting deviations from expected application behavior
The JA4H fingerprint is intentionally modular. Depending on deployment and configuration, it can reflect application identity, cookie structure, or user-level behavior without logging sensitive payload data. JA4H is useful when combined with lower-level fingerprints:
- Pairing
ja4hwithja4andja4sties HTTP behavior to TLS libraries - Pairing
ja4hwithja4thighlights mismatches between claimed and observed client behavior - Tracking changes in
ja4hover time can surface application updates or injected tooling

Figure 5: JA4H fingerprint structure. Image courtesy of the FoxIO JA4 GitHub repository.
ja4ssh.log: JA4SSH
When the JA4 package is loaded, Zeek produces a dedicated ja4ssh.log. JA4SSH fingerprints ses sion activity rather than identifying the SSH client or server software itself. It profiles SSH session be havior based on packet sizes and directionality over time. Zeek users can look at the HASSH package to fingerprint SSH applications themselves.
ja4ssh: SSH session fingerprint
The ja4ssh value fingerprints an SSH session by observing encrypted packet sizes, padding behavior, and which side is driving the interaction. These characteristics are derived from the SSH protocol’s packet framing and remain visible even though the payload is encrypted. ja4ssh is effective at distin guishing between:
- Interactive SSH sessions
- Reverse shells
- SCP or SFTP file transfers
- SSH tunnels and port forwarding
- Automated or scripted SSH activity
Because SSH uses encrypted messages rather than an encrypted tunnel, certain transport-level signals (such as TCP ACK directionality) remain observable. JA4SSH leverages these signals to classify session behavior with high confidence. JA4SSH addresses a gap in traditional SSH logging, which often answers who connected where, but not what kind of SSH activity occurred.
Use cases:
- Detecting reverse SSH shells in otherwise normal environments
- Flagging interactive shells where only file transfers are expected
- Monitoring SFTP-only workflows for deviations
- Identifying lateral movement over SSH without decrypting traffic
JA4SSH works entirely on encrypted traffic and does not require payload inspection, credentials, or protocol violations.

Figure 6: JA4SSH fingerprint structure. Image courtesy of the FoxIO JA4 GitHub repository.
ja4d.log: JA4D (DHCP fingerprinting)
JA4D was released in November 2025, making it the most recent addition to the JA4 family. When the JA4 package is loaded, Zeek creates a ja4d.log DHCP message fingerprints and other DHCP-related fields.
ja4d: DHCP client fingerprint
The ja4d value fingerprints how a DHCP client constructs its messages, based on the message type and selected options. It encodes:
- A normalized DHCP message type
- The max DHCP message size
- Flags indicating whether a requested IP is present and whether an FQDN is included
- The DHCP options list
- The parameter request list
JA4D is logged per DHCP message, not per full lease conversation. That makes it easy to spot patterns across many short-lived or incomplete exchanges. ja4d is useful for:
- Identifying different DHCP client implementations and OS stacks
- Spotting unusual or custom DHCP clients on the network
- Detecting misconfigured or rogue DHCP behavior
- Grouping systems by how they request addresses, not just by which addresses they get
Because ja4d.log also carries uid, client_mac, requested_ip, vendor_class_id, and hostname, it also serves as a convenient pivot into dhcp.log, conn.log, ARP data, and asset inventories.

Figure 7: JA4D fingerprint structure. Image courtesy of the FoxIO JA4 GitHub repository.
Why JA4 Matters in Zeek
The JA4 package extends Zeek’s logging with fingerprints that don’t depend on IP addresses, domain names, or encryption. A client’s JA4 fingerprint stays the same whether it’s connecting from a VPN or rotating through proxies. A server’s JA4S remains consistent even as certificates and DNS records change.
Paired with JA4T for OS detection, JA4H for HTTP behavior, JA4SSH for session classification, and JA4D for DHCP profiling, these fingerprints provide stable pivot points in traffic that’s inherently unstable. For Zeek deployments, that’s the difference between tracking individual indicators and tracking behavior.
Ready to start fingerprinting? Install the package and see what your traffic reveals.
Resources:
- Install the package:
zkg install zeek/foxio/ja4 - Review the JA4 GitHub repository for technical specifications
- Check the FoxIO blog for detection use cases and analysis techniques
- Join the Zeek Slack or Discourse forum to discuss JA4 integration and share detection strategies
RSS - Posts