Skip to content

Proposal: new JA4+ method for an "ephemeral-extension-invariant" stable client fingerprint (tentative name JA4E) #303

Description

@giuseongit

Context

About six months ago (Jan 2, 2026) ntop published an analysis ("Is JA4 Now Obsolete?", https://www.ntop.org/is-ja4-now-obsolete/) showing that JA4 can produce different fingerprints for the same client across consecutive connections. Their reproduction used Safari as the example: Safari uses the TLS 1.3 pre-shared key extension (RFC 8446) to resume a previous session, and the presence/parameters of that extension (along with related "ephemeral" extensions like session_ticket and padding) change the JA4_b hash even though the underlying client/library is unchanged.

We want to flag that Safari is just the example ntop happened to use — we've independently observed the same instability (fresh handshake vs. resumed handshake producing different JA4 values for the same client) across several different browsers, not just Safari. This isn't a Safari-specific quirk, it's a structural property of how JA4 treats connection-state-dependent extensions.

ntop's own mitigation in nDPI is an opt-in flag (tls,metadata.ja_ignore_ephemeral_tls_extn) that strips a defined set of "ephemeral" extensions (session ticket, pre-shared key, padding) before computing JA4, restoring a stable fingerprint for the same client across reconnects. Their writeup explicitly frames this as a stopgap "until a JA5 standard is published."

Prior art / existing implementation

We ran into this same instability problem and needed a stable JA4, so we already implemented and upstreamed a fix as a PR to the fingerproxy Go library:

wi1dcard/fingerproxy#42

Summary of that implementation, for reference:

  • Adds an opt-in StableJA4Fingerprint alongside the existing raw JA4, leaving raw JA4 behavior unchanged.
  • Excludes three extensions from both the extension count and the extension hash input: padding (0x0015), session_ticket (0x0023), pre_shared_key (0x0029) — the same set ntop identifies as ephemeral.
  • Includes test coverage for full vs. resumed/PSK handshakes (Chrome), each individually-ignored extension, and confirmation that non-ephemeral extensions still affect the stable hash as expected.

This isn't meant as "the" reference implementation, just evidence that (a) the problem is reproducible and fixable with a small, well-scoped rule, and (b) at least two independent parties (ntop/nDPI and us) converged on excluding the same three extensions.

Problem

JA4 was designed to be both unique and stable for a given TLS client implementation. The current spec, however, does not define how to treat extensions whose presence/content varies per-connection for reasons unrelated to client identity (session resumption, ticket rotation, padding length). This means:

  • Different parties invent their own ad-hoc fix (ntop/nDPI, and separately us against fingerproxy), fragmenting the ecosystem instead of having one canonical answer.
  • Anyone relying on JA4 for fingerprint-based grouping/detection (one of JA4's stated use cases) gets false negatives when a stable client appears as multiple distinct fingerprints across resumed sessions.

Proposal

We'd like to propose a new JA4+ method — a connection-stable variant of JA4 that normalizes or excludes a well-defined set of "ephemeral" TLS extensions before hashing, so the same client/library produces the same fingerprint across session-resumption events.

Conceptually this would sit alongside JA4 the same way JA4S sits alongside JA4 today: same family, distinct, explicitly-scoped purpose. We are not proposing to change JA4 itself — backward compatibility and existing detections built on JA4 should be unaffected.

Open questions we'd like FoxIO's input on, since JA4+ naming/spec is maintained by FoxIO:

  1. Naming: JA4S is already taken (TLS Server fingerprinting), so we can't reuse "stable" => JA4S as we originally considered. We're tentatively suggesting JA4E ("ephemeral-extension-invariant"), but defer to your judgement on the letter/naming convention.
  2. Scope of "ephemeral": should the initial set match nDPI's and our fingerproxy PR's (session_ticket / RFC 9149, pre_shared_key / RFC 8446, padding / RFC 7685), or should it be extensible/versioned as new ephemeral extensions appear in future TLS revisions?
  3. Relationship to JA4 vs JA5: should this be a JA4+ sibling method, or fold into whatever JA5 ends up being? Happy to align with whatever direction FoxIO is already planning.

We are raising this as a specification proposal, not a documentation PR, since JA4+ naming and the formal definition of each method are maintained by FoxIO and subject to licensing/trademark considerations (per the JA4+ README licensing section). Once there's agreement on the name and the precise extension list/algorithm, we're happy to help with spec docs and/or a reference implementation.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions