JustBrowser
Tutorials12 min read

TLS GREASE & Extension Order: Fix Antidetect JA4 Leaks (2026)

JustBrowser Platform Team·

Last month a scraping engineer messaged our support channel with a Wireshark capture. They'd been getting blocked on Cloudflare-protected sites despite passing every JavaScript fingerprint test — CreepJS, Pixelscan, BrowserScan, all green. The capture showed the problem in about four seconds.

Their ClientHello had no GREASE values. None.

Chrome inserts random GREASE values into every TLS handshake. It's been doing this since 2016. Any detection system comparing their fingerprint against known Chrome patterns would see a ClientHello claiming to be Chrome 125 with zero GREASE — something that doesn't exist in the wild. Red flag. Automatic. This is exactly the kind of network-layer fingerprinting that wrapper-based antidetect browsers can't address.

This tutorial breaks down GREASE and extension ordering: what they are, why JA4 fingerprints catch them, how to test your setup, and what native antidetect browsers do differently. Fair warning — we're going deep into the weeds here. Probably too deep. But I've watched too many people get blocked by something they never thought to check, and I'd rather over-explain than leave you guessing.

What We're Learning

By the end of this, you'll understand:

  • How GREASE values work and why Chrome uses them
  • Why TLS extension order differs between browsers
  • How JA4 fingerprints detect GREASE and ordering mismatches
  • How to test your own setup for these specific leaks
  • What architectural changes fix these issues (spoiler: it requires source-level control)

You'll also have a concrete checklist for auditing any antidetect browser's TLS behavior.

Prerequisites

  • Basic understanding of TLS handshakes (ClientHello, supported ciphers, extensions) — see our TLS fingerprinting primer
  • Familiarity with JA4 fingerprinting concepts — read that first if you're new to TLS fingerprinting
  • A packet capture tool (Wireshark, tcpdump, or tls.peet.ws for browser-based capture)
  • An antidetect browser to test (your current tool or JustBrowser's 7-day trial)

Step 1: Understand What GREASE Actually Does

GREASE stands for Generate Random Extensions And Sustain Extensibility. RFC 8701 formalized it, but Chrome implemented GREASE internally years earlier.

The problem GREASE solves: network middleboxes (firewalls, load balancers, proxies) sometimes break when they see TLS extension IDs they don't recognize. When the TLS spec adds new extensions, these middleboxes might reject the connection because the extension ID "looks wrong."

Chrome's solution: randomly insert fake extension IDs from a reserved range into every handshake. If middleboxes reject these fake IDs, operators notice and fix their equipment. This keeps the ecosystem healthy for future real extensions.

The reserved GREASE values follow a specific pattern: 0x?A?A where ? can be any hex digit. So 0x0A0A, 0x1A1A, 0x2A2A, through 0xFAFA. Sixteen possible values total.

Here's what Chrome does with them:

  • Cipher suites: One GREASE value inserted in the cipher list
  • Extensions: One GREASE value inserted in the extension list
  • Supported groups: One GREASE value inserted in the elliptic curve list
  • Signature algorithms: Sometimes one GREASE value here too

The specific GREASE value chosen is random per-connection, but the pattern — inserting GREASE in these specific slots — is consistent across all Chrome versions since mid-2016.

Firefox doesn't use GREASE. Safari doesn't either. This is Chrome-specific.

And here's what drives me nuts: most antidetect browser marketing talks about canvas fingerprints and WebGL like they're the whole game. Meanwhile detection systems are reading your TLS handshake before a single pixel renders. The handshake tells them everything. If your antidetect browser claims to be Chrome but doesn't send GREASE values, that's a visible mismatch. Sends GREASE but always the same value instead of rotating? Detectable. Claims Firefox but sends GREASE anyway? Instant flag.

Step 2: Understand Extension Ordering

TLS extensions appear in a specific order in the ClientHello. This order isn't random — each browser has its own consistent sequence.

Chrome 125 (example) sends extensions roughly like this:

  1. server_name (SNI)
  2. extended_master_secret
  3. renegotiation_info
  4. supported_groups
  5. ec_point_formats
  6. session_ticket
  7. application_layer_protocol_negotiation (ALPN)
  8. status_request
  9. signature_algorithms
  10. signed_certificate_timestamp
  11. key_share
  12. psk_key_exchange_modes
  13. supported_versions
  14. compress_certificate
  15. GREASE extension
  16. padding

Firefox uses a different order. Safari uses another. And critically, this order is stable within a browser version — it doesn't change per-connection.

JA4 fingerprints capture this. The JA4 format includes a hash of the sorted extension list, but the raw fingerprint (JA4_r) preserves original order. Detection systems compare your extension order against known baselines.

The detection logic: If your JavaScript says Firefox but your extension order matches Chrome's sequence, the fingerprint is inconsistent. This isn't subtle. Extension order alone can distinguish browser families with high confidence.

(I spent a frustrating afternoon once watching a profile get blocked repeatedly. The user agent was Firefox, the canvas said Firefox, the WebGL said Firefox. The extension order was pure Chrome. Three hours I'll never get back.)

Step 3: Capture Your Own ClientHello

Let's see what your antidetect browser actually sends.

Option A: Browser-based capture (easier)

  1. Open tls.peet.ws in your antidetect browser
  2. The site captures your TLS fingerprint and displays the raw ClientHello
  3. Look for the extension list — note the order and any GREASE values

Option B: Wireshark (more control)

  1. Start Wireshark, filter for tls.handshake.type == 1 (ClientHello only)
  2. Navigate to any HTTPS site in your antidetect browser
  3. Find the ClientHello packet, expand the TLS layer
  4. Look at "Extension: ..." entries in order

What you're looking for:

  • GREASE present? Look for extensions in the 0x?A?A pattern
  • GREASE position? Chrome puts GREASE near the end of the extension list
  • GREASE rotation? Refresh and capture again — the value should change
  • Extension order? Write down the sequence, compare against known baselines

This part is tedious. I won't pretend otherwise.

Option C: JA4 databases

Sites like ja4db.com maintain fingerprint databases. You can compare your captured fingerprint against known browser populations. If your fingerprint doesn't match any real browser, you're standing out.

Step 4: Compare Against Expected Baselines

Here's what real Chrome looks like (simplified):

Chrome 125 on Windows 10:
- Extensions: server_name, extended_master_secret, renegotiation_info,
  supported_groups, ec_point_formats, session_ticket, alpn, status_request,
  signature_algorithms, signed_certificate_timestamp, key_share,
  psk_key_exchange_modes, supported_versions, compress_certificate,
  GREASE (0x4A4A or similar), padding
- GREASE in cipher list: Yes (one value)
- GREASE in supported_groups: Yes (one value)
- Total extensions: ~16

And Firefox 124:

Firefox 124 on Windows 10:
- Extensions: server_name, extended_master_secret, supported_groups,
  ec_point_formats, session_ticket, alpn, status_request, delegated_credentials,
  key_share, supported_versions, signature_algorithms, psk_key_exchange_modes,
  record_size_limit
- GREASE: None (Firefox doesn't use GREASE)
- Total extensions: ~13

See the differences? Extension count, order, GREASE presence — all vary by browser family.

Now compare your captured ClientHello against these baselines. If you're spoofing Firefox but your fingerprint looks like Chrome, you've found the leak.

Step 5: Understand Why Wrapper Browsers Can't Fix This

Here's the architectural problem.

Antidetect browsers that work above the engine run on top of Chromium. They inject JavaScript to intercept fingerprinting APIs — canvas, WebGL, fonts, navigator properties. That's their modification layer.

But TLS happens in the network stack. Specifically, in BoringSSL for Chromium-based browsers. The ClientHello is constructed and sent before any page loads, before any JavaScript runs, before the wrapper's interception layer even activates.

The wrapper has no hook to modify:

  • Cipher suite list and order
  • Extension list and order
  • GREASE value insertion
  • Signature algorithms
  • Supported groups

These are hardcoded in BoringSSL's connection setup. The wrapper operates at the application layer; TLS operates at the transport layer. Different levels, no overlap.

Some wrappers claim to "randomize" TLS fingerprints. This is worse than useless — honestly, it's embarrassing that anyone markets this with a straight face. Random fingerprints don't match any real browser population. Detection systems flag anomalies just as readily as mismatches — possibly more readily. You're not blending in; you're broadcasting "I'm using an evasion tool."

(I've seen marketing copy claiming "military-grade TLS protection" that, when tested, produced fingerprints matching nothing in the JA4 database. Cool story. Doesn't help.)

Look, I get it. TLS is hard. Most people don't want to think about BoringSSL or cipher suites. But if you're paying for an antidetect browser that can't touch the network layer, you're paying for half a solution.

Step 6: What Native Antidetect Browsers Do Differently

JustBrowser is a native C++ Chromium fork. We modify BoringSSL directly.

When you create a profile claiming to be Chrome on Windows:

  • The cipher list matches real Chrome, in order
  • The extension list matches real Chrome, in order
  • GREASE values are inserted in the correct slots
  • GREASE values rotate randomly per-connection
  • Signature algorithms match the claimed version

When you create a profile claiming to be Firefox:

  • No GREASE values (Firefox doesn't use them)
  • Extension order matches Firefox's sequence
  • Cipher preferences match Firefox's TLS stack

The fingerprint at the network layer is consistent with the fingerprint at the JavaScript layer. No mismatch signal.

This took us almost a year to implement properly. I'm not going to pretend that was fun. Maintaining TLS profiles across browser versions is ongoing work — every Chrome update potentially shifts the fingerprint baseline, and we've had a few late nights scrambling when a new version dropped. But the alternative was shipping a product that leaks identity through the socket. That felt dishonest. And frankly, if we were going to cut corners on the hard stuff, why bother building a native fork at all?

Common Errors and How to Fix Them

Error: No GREASE values in ClientHello while spoofing Chrome

What causes it: Your antidetect browser doesn't implement GREASE, or it's using a Firefox-based TLS stack while claiming Chrome.

The fix: Use a native antidetect browser that controls the TLS layer. There's no workaround at the application level. JustBrowser's 7-day trial includes full TLS fingerprint matching — enough to test whether this fixes your blocks.

Error: GREASE values don't rotate between connections

What causes it: Some tools hardcode a single GREASE value instead of randomizing per-connection.

The fix: Same as above — this requires source-level control over BoringSSL. Capture multiple ClientHellos and verify the GREASE values differ.

Error: Extension order matches Chrome while spoofing Firefox

What causes it: The antidetect browser is built on Chromium and can't modify the extension sequence.

The fix: Native browser fork. Or stop claiming to be Firefox and spoof a Chrome identity that matches your actual TLS behavior — but that limits your fingerprint diversity.

Error: JA4 fingerprint matches no known browser

What causes it: Randomization features, partial modifications, or buggy implementations that produce synthetic fingerprints.

The fix: Disable randomization. Match a specific, real browser population. Detection systems flag anomalies; blending in requires looking like something that actually exists. I know "disable the feature you paid for" sounds counterintuitive. But synthetic fingerprints are a liability. For ad verification workflows at scale, consistent real fingerprints outperform synthetic randomization every time.

Next Steps

You've got the fundamentals on GREASE and extension ordering. Maybe more than you wanted. Some directions to explore:

  • HTTP/2 fingerprinting: After TLS, the HTTP/2 SETTINGS frame is another network-layer signal. JA4H captures this. We cover it in our TLS cipher order guide.
  • Session resumption: TLS session tickets and 0-RTT behavior vary by browser. Another detection surface.
  • Full fingerprint testing: Run your profiles against CreepJS, Pixelscan, and BrowserScan to verify JavaScript fingerprints match your TLS identity.

For tracking conversions without feeding fingerprint data back to platforms, JustAnalytics handles privacy-first analytics. And if you're running paid campaigns and concerned about bot traffic exploiting fingerprint inconsistencies, ClickzProtect detects click fraud at the network layer — including traffic with mismatched TLS signatures.

Frequently Asked Questions

What is TLS GREASE and why does it matter for antidetect browsers?

GREASE (Generate Random Extensions And Sustain Extensibility) is Chrome's mechanism for preventing network middleboxes from breaking when new TLS features appear. Chrome inserts random GREASE values in specific slots of the ClientHello — cipher suites, extensions, supported groups. These random values follow a predictable pattern that detection systems recognize. If your antidetect browser doesn't implement GREASE correctly, or uses Firefox's TLS stack while claiming to be Chrome, the mismatch is visible in JA4 fingerprints.

How does extension ordering differ between Chrome and Firefox?

Chrome and Firefox send TLS extensions in different orders, and these orders are consistent within each browser. Chrome sends supported_versions early, then key_share, then specific extensions in a fixed sequence. Firefox uses a different arrangement. JA4 hashes extension order directly — if your profile claims Firefox but sends Chrome's extension sequence, detection systems flag the inconsistency immediately.

Can wrapper antidetect browsers fix GREASE and extension order issues?

No. Wrapper and extension-based antidetect browsers can't modify TLS behavior because the handshake happens in the browser's network stack — BoringSSL for Chromium — before any JavaScript runs. They control what happens on the page, not what happens in the socket. Fixing GREASE and extension order requires modifying the browser at the source level, which only native forks can do.

How do I test if my antidetect browser leaks through GREASE or extension order?

Use a TLS fingerprint analyzer like ja4db.com or tls.peet.ws to capture your ClientHello. Check whether GREASE values appear in the expected slots (cipher suites, extensions, supported groups) and whether they rotate per-connection like real Chrome. Compare your extension order against known browser baselines. If you're spoofing Firefox but your extension order matches Chrome, you're leaking identity.


Try JustBrowser

Native Chromium antidetect browser — not extension-based. Real C++ engine patches at the canvas / WebGL / font / TLS layer, so 40+ identity parameters are genuine, not faked. REST API for Playwright, Puppeteer, Selenium. 7-day free trial, card required — then $9.99/month or $99.99/year, unlimited profiles, free team seats.

Get started → · How it differs from Multilogin / GoLogin / AdsPower

Ready to manage multiple accounts?

Seven days free, then $9.99/month — one plan, everything included.

We'd like to use Google Analytics, a Google service, to understand how our website is used. It sets two cookies in your browser and runs only if you click Accept. You can change your choice at any time with Cookie settings. Cookie Policy

Sign-in cookies and the cookie that remembers this choice are always on; the website needs them to work.

Google Analytics, a Google service, helps us understand how our website is used. It sets two cookies, _ga and _ga_TVZHQ99TZW. It is now onoff in this browser. If your browser sends a Global Privacy Control or Do Not Track signal, it stays off. Cookie Policy