HTTP/3 QPACK Dynamic Table State as a Session Linker: How Header Compression State Links Sessions Even When Connection ID Changes

BadB

Professional
Messages
2,545
Reaction score
2,683
Points
113
How header compression state in QPACK can link sessions even when the Connection ID changes.

Introduction: The Invisible Thread in QUIC​

You think you've changed your IP address, updated your TLS fingerprint, reset your cookies, and even changed your QUIC Connection ID — and now you're "clean"?
Think again.

HTTP/3 hides an invisible thread that binds your sessions at the protocol level, deeper than JavaScript or even TLS. This is the state of the dynamic QPACK table.

Most carders don't know about it. Those who do consider it an "internal optimization." But in reality, QPACK is a hidden identification mechanism that makes changing your Connection ID useless if you don't manage your compression state correctly.

In this article, we'll explore how QPACK works, why it binds sessions, and what errors can kill carding at the start.

Part 1: What is QPACK and why is it needed?​

HTTP/3 runs on top of QUIC, a transport protocol built on UDP. To speed up header transfers, HTTP/3 uses QPACK, a compression mechanism based on HPACK (from HTTP/2) but adapted to the specifics of QUIC.

QPACK uses two tables:
  1. Static table - predefined pairs (for example, :method: GET).
  2. Dynamic table - populated in real time with new headers (e.g. user-agent, x-client-id).

The key point: the dynamic table is persisted between requests within a single HTTP/3 session. And this is where the problem begins.

Part 2: How QPACK Links Sessions Even When the Connection ID Changes​

🔹 Connection ID ≠ Session​

QUIC allows you to change the Connection ID without breaking the connection—this is necessary for roaming (switching between Wi-Fi and mobile networks). Many carders think, "Changing the CID means starting a new session."
This is an illusion.

Because the QPACK table is tied not to the CID, but to the internal state of the HTTP/3 stream. Until the TCP-like connection (in QUIC, this is the "connection context") is closed, the dynamic table persists.

🔹 Failure Scenario​

  1. You visit target.com with IP A → send User-Agent: Chrome/125.
  2. QPACK adds this header to the dynamic table at index 64.
  3. You change the proxy, update the CID, but do not close the QUIC connection.
  4. On the next request, you send the header as a Literal Header Field with Index 64.
  5. The server sees: "This client already knows that index 64 = User-Agent."
    The session is associated, despite the new IP and CID.

💀 A real case:
A carder used a residential proxy with an IP rotation every 5 minutes.
All transactions on the Razer Gold were connected via QPACK and blocked as "repeated fraud."

Part 3: Implementation Differences Between Browsers​

Not all browsers behave the same way - and this can be exploited.
BrowserQPACK behavior
ChromeSaves the dynamic table until the tab is completely closed. Even if the proxy changes, the table remains active.
FirefoxClears the table when the origin changes (for example, moving from google.com to razer.com).
SafariUses a limited table size (64 records) and aggressively purges old records.
Practical consequence:
If you impersonate Chrome, but your QPACK table is "cleared" when you change domains, you are marked as Firefox or a fake profile.

Part 4: Three Fatal Mistakes Carders Make (and How to Fix Them)​

❌ Mistake #1: "I changed my CID, I'm clean."​

Problem:
Carders rely on changing the QUIC Connection ID as a "hard reset," but the HTTP/3 session remains the same.

✅ Fix:
  • Close the HTTP/3 connection completelybetween operations:
    • In the anti-detect browser: restart the profile (not just the tab!),
    • Or use different profiles for each session.
  • Make sure that the TLS session is also not reused (session resumption = off).

❌ Mistake #2: Ignoring Heading Order​

Problem:
QPACK not only stores headers, but also the order in which they were added. If you sent User-Agent → Accept-Language in the first session and the opposite in the second, the server will notice the discrepancy.

✅ Fix:
  • Use a fixed header order across all sessions,
  • In Dolphin Anty / Multilogin: enable the option "Preserve header order"
  • Don't allow extensions or scripts to modify headers.

❌ Mistake #3: Lack of QPACK state validation​

Problem:
Carders don't check that their profile actually starts with a "clean" QPACK table.

✅ Fix:
  • Use Wireshark + qlogto analyze HTTP/3 traffic:
    1. Run the capture with the quic filter,
    2. Find HEADERS frames,
    3. Check if Indexed Header Fields are used (indexes > 61 = dynamic table).
  • If in the first session after the start there are indexes >61, your profile is not clean.

Part 5: A Practical Checklist for a Carder​

StepAction
1. Session isolationEach hit is a new profile (not a tab!)
2. Disabling session resumptionIn the proxy/TLS settings, disable reuse.
3. Fixed order of headingsSet it up manually, don't rely on the browser
4. Validation via WiresharkMake sure the first headings are Literal, not Indexed.
5. Simulate the target browserChrome = long-lived table; Firefox = clean by origin

Conclusion: Hidden Protocol Memory​

QPACK isn't just optimization. It's hidden HTTP/3 memory that remembers you even when you think you've erased all traces.

Those who ignore the dynamic table state are doomed to session binding.
Those who manage it gain an advantage: their profiles appear brand new, even on repeated visits.

Remember: in 2026, security isn't about changing IP addresses. It's about controlling every byte of the protocol.

Good luck with your carding.
 
Top