browserforensics
Back to all articles

Chrome v20 app-bound encryption, explained

2026-06-21 · 4 min

Chrome 127 added a second cookie-encryption scheme on top of the classic DPAPI one. The goal was explicit: stop other processes — infostealers included — from reading a logged-in user's cookies just because they run as that user. The mechanism, app-bound encryption, ties the key to a signed chrome.exe and pushes part of the unwrap behind a privileged service. This post covers what v20 actually is and how far it reduces to offline crypto, building on how Chromium encrypts cookies on Windows.

What changed in Local State

The old v10 key is still there. v20 adds a second wrapped key alongside it:

{
  "os_crypt": {
    "encrypted_key": "RFBBUEkBAAAA...",
    "app_bound_encrypted_key": "QVBQQgEAAADQ..."
  }
}

Base64-decode app_bound_encrypted_key and the first four bytes are the ASCII tag APPB (compare the v10 key's DPAPI prefix). Strip it and what remains is a multi-layer blob — not a single DPAPI envelope.

The v20 cookie value format

On the wire a v20 value looks almost identical to v10:

BytesMeaning
0..3version tag — ASCII v20
3..1512-byte AES-GCM nonce
15..n-16ciphertext
n-16..n16-byte GCM authentication tag

Same AES-256-GCM, same nonce-then-tag layout. Two differences matter:

  • It is decrypted with the app-bound key, not the encrypted_key.
  • The decrypted plaintext is prefixed with a 32-byte SHA-256 hash of the cookie's host. Strip those 32 bytes to get the actual value. (Chrome uses it as a binding check; for recovery you just discard it.)

Unwrapping app_bound_encrypted_key

After stripping APPB, the key is wrapped in three nested layers:

  1. SYSTEM DPAPI — outer layer, sealed under the machine DPAPI key.
  2. User DPAPI — inner layer, sealed under the user's DPAPI masterkey (the same family of secret as the v10 chain).
  3. App-bound transform — the innermost blob, whose first byte is a flag selecting how the final key was sealed.

The flag byte decides everything downstream:

FlagSchemeOffline?
1AES-256-GCM with a hard-coded key (publicly known, b31c6e24…0284787)Yes
2ChaCha20-Poly1305 with another hard-coded keyYes, in principle
3Key wrapped via the online CNG / elevation serviceNo

Flags 1 and 2 are reducible to math: the keys are public, so once both DPAPI layers are off, decrypting the innermost blob is a plain AEAD operation. Flag 3 is not — the actual unwrap happens inside a privileged service.

The elevation service is the whole point

For flag 3, the innermost step is handled by Chrome's elevation service, which verifies the caller is a signed chrome.exe before returning the key. That signature check is the design intent of app-bound encryption: it is what stops a stealer process — running as the same user, holding the same DPAPI masterkey — from getting the key the way it could with v10. There is no file you can carry away that substitutes for a live, trusted call to that service.

What is actually offline

Honest summary: v20 is partial and version-dependent offline.

LayerNeeded inputFrom acquired files?
SYSTEM DPAPImachine DPAPI keyYes — from the SECURITY hive
User DPAPIuser masterkey + NT hash/SIDYes — see the DPAPI chain
Flag 1 / 2 transformhard-coded key (public)Yes
Flag 3 transformlive elevation serviceNo

So even with a perfect disk image, a flag-3 key does not come out without the running machine. Flag-1 (and 2) keys do — provided you can peel both DPAPI layers first. Which flag a given profile uses depends on the Chrome build, so treat "can I recover this v20 key offline?" as a per-image question, not a yes/no for the scheme.

What the tool does (and does not)

BrowserForensics ships an experimental v20 method. It does not attempt the DPAPI layers in the browser — give it the app-bound blob with both DPAPI layers already removed (do that with your existing offline DPAPI workflow). From there it:

  • Reads the flag byte.
  • For flag 1, unwraps the key in-browser with WebCrypto AES-GCM using the public hard-coded key. The GCM tag self-validates — a wrong input fails authentication rather than returning garbage, the same trust property as the DPAPI HMAC check.
  • For flags 2 and 3, it reports a clear error rather than pretending.

The recovered key then decrypts v20 cookie values directly — the 32-byte host-hash strip is handled for you, so what you get back is the cookie value. End to end this runs in a tab, like the v10 in-browser decryptor; no key or password leaves the page.

Further reading