Skip to content

tls_inspector: fix GREASE filtering in JA4_c signature algorithms - #46658

Open
dangle1 wants to merge 1 commit into
envoyproxy:mainfrom
dangle1:fix/ja4-c-grease-sigalgs
Open

tls_inspector: fix GREASE filtering in JA4_c signature algorithms#46658
dangle1 wants to merge 1 commit into
envoyproxy:mainfrom
dangle1:fix/ja4-c-grease-sigalgs

Conversation

@dangle1

@dangle1 dangle1 commented Aug 11, 2026

Copy link
Copy Markdown

Summary

The JA4 fingerprint's third component hashes the ClientHello's extension list joined to its signature_algorithms list. Per the JA4 spec, GREASE codepoints must be excluded everywhere they appear — including in signature_algorithms.

getJA4ExtensionHash already applies isNotGrease to extension type IDs, and getJA4CipherHash, countCiphers, and countExtensions apply it to their respective inputs. The signature_algorithms collection loop was the sole exception, pushing every 16-bit codepoint from the extension body unconditionally.

Clients that inject a GREASE value into signature_algorithms (e.g. Chrome's per-handshake random GREASE selection, drawn from the 16 reserved code points 0x0a0a, 0x1a1a, …, 0xfafa) therefore produce a different JA4_c hash per connection while all other parts of the fingerprint are identical — resulting in many-to-one hash collapse when compared against spec-compliant implementations.

Fix

Guard the sig_algs.push_back(sig_alg) call in getJA4ExtensionHash with isNotGrease(sig_alg), matching the treatment already applied everywhere else in the file.

Test plan

  • Added TEST(JA4Fingerprinter, GreaseValueFilteredFromSignatureAlgorithms) in ja4_fingerprint_test.cc that constructs two `SSL_CLIENT_HELLO`s identical except for a GREASE codepoint (`0x0a0a`) in `signature_algorithms` and asserts `JA4Fingerprinter::create` produces the same fingerprint for both.
  • `bazel test //test/extensions/filters/listener/tls_inspector:ja4_fingerprint_test` passes locally.

Notes

  • No existing entry in the `JA4_TEST_VECTORS` table in `tls_inspector_ja4_test.cc` contains a GREASE codepoint inside its `signature_algorithms` extension body — all GREASE bytes in those captures live in extensions/versions/keyshare slots, which are already filtered correctly — so its pinned expected hashes remain valid.
  • This change was drafted with AI assistance and reviewed by the author.

The JA4 fingerprint's third component hashes the ClientHello's extension
list joined to its signature_algorithms list. Per the JA4 spec, GREASE
codepoints must be excluded everywhere they appear -- including in
signature_algorithms. `getJA4ExtensionHash` already applies `isNotGrease`
to extension type IDs, and `getJA4CipherHash`, `countCiphers`, and
`countExtensions` apply it to their respective inputs. The
signature_algorithms collection loop was the sole exception, pushing every
16-bit codepoint from the extension body unconditionally.

Clients that inject a GREASE value into signature_algorithms (e.g.
Chrome's per-handshake random GREASE selection) therefore produce a
different JA4_c hash per connection while all other parts of the
fingerprint are identical -- resulting in many-to-one hash collapse when
compared to spec-compliant implementations.

Guard the `sig_algs.push_back` call with `isNotGrease(sig_alg)`, matching
the treatment already applied elsewhere in the file. Adds a regression
test that asserts JA4 fingerprint equality between two ClientHellos that
differ only in the presence of a GREASE codepoint in signature_algorithms.

Spec reference:
https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md

Note: this change was drafted with AI assistance and reviewed by the author.
Signed-off-by: dangle <dangle@pinterest.com>
@dangle1
dangle1 requested a deployment to external-contributors August 11, 2026 22:04 — with GitHub Actions Waiting
@repokitteh-read-only

Copy link
Copy Markdown

Hi @dangle1, welcome and thank you for your contribution.

We will try to review your Pull Request as quickly as possible.

In the meantime, please take a look at the contribution guidelines if you have not done so already.

🐱

Caused by: #46658 was opened by dangle1.

see: more, trace.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant