Repository navigation
fix(decryptor): correct macOS v10 cookie decryption (wrong key + M130 domain hash) - #3
Merged
Merged
Conversation
Two independent bugs produced garbage cookie values on Chrome M130+ / macOS; both are required for a clean decrypt. Bug A (wrong AES key): getChromeSafeStoragePassword() base64-decoded the Keychain "Chrome Safe Storage" password before PBKDF2. The macOS v10 scheme uses that password STRING as-is as the PBKDF2 secret, so decoding it derived a wrong 16-byte key and corrupted the entire plaintext. Pass the raw string on both the primary and fallback return paths. Bug B (unstripped domain hash): Chrome M130+ prepends a 32-byte SHA-256(host_key) to the plaintext before encryption. After AES decrypt and PKCS7 unpad, strip those 32 bytes only when they equal sha256(host_key); older payloads without the prefix are left untouched for backward compatibility. This threads host_key into decryptValue() and its extractor call sites. Unblocks authenticated auth-curl requests (login-gated watchtell alarm). Tests use synthetic fixtures only (no real cookies/Keychain data) and assert the conditional strip: present -> stripped, absent -> untouched.
The security CI job failed with `npm audit` HTTP 400 "Invalid package tree, run npm install to rebuild your package-lock.json". The lockfile was stale: the 1.1.0/1.1.1 release commits bumped package.json but never updated package-lock.json, leaving its root version at 0.0.0-development and drifting package metadata (devOptional vs optional). Regenerated via npm install so the tree validates; `npm ci` is now in sync.
The npm bundled with Node 18 calls the retired quick-audit endpoint (/-/npm/v1/security/audits/quick), which now returns HTTP 400 "Invalid package tree", failing the security job even with an in-sync lockfile. Upgrade to the latest npm before `npm ci`/`npm audit` so it uses the bulk advisory endpoint. The audit stays blocking (--audit-level high).
npm@latest (12.x) requires Node >=22.22 and failed with EBADENGINE on Node 18. Bump the security job to Node 22.x and pin npm@11, which uses the bulk advisory endpoint (the retired quick-audit endpoint returns 400). Audit stays blocking (--audit-level high).
npm 11 reached the bulk advisory endpoint but failed to decode its gzipped response. Node 22.x on the runner (22.23.1) satisfies npm@latest (12.x, requires Node >=22.22), whose updated fetch stack parses the gzipped audit response. Audit stays blocking (--audit-level high).
The npm-audit gate hits a registry-side gzip-decode failure on the bulk advisory endpoint that no npm-version change fixes; it is tracked as a separate cleanup task. Revert the CI experiments so this PR carries only the decryption fix, tests, and the legitimate package-lock.json refresh.
github-actions Bot
pushed a commit
that referenced
this pull request
Jul 26, 2026
# [1.2.0](v1.1.1...v1.2.0) (2026-07-26) ### Bug Fixes * **decryptor:** correct macOS v10 cookie decryption (wrong key + M130 domain hash) ([#3](#3)) ([f4f6ed5](f4f6ed5)) ### Features * **auth-curl:** add --max-time and --connect-timeout passthrough to curl ([#4](#4)) ([5e46715](5e46715)) * **auth-curl:** forward unknown curl flags to the underlying curl ([#6](#6)) ([6739734](6739734))
|
🎉 This PR is included in version 1.2.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Chrome M130+ on macOS was producing garbage (binary) cookie values because of two independent bugs in the v10 decryption path. Both must be fixed together — fixing either alone still yields garbage.
Bug A — wrong AES key (
src/decryptor.ts)getChromeSafeStoragePassword()base64-decoded the KeychainChrome Safe Storagepassword before feeding it to PBKDF2. The macOS v10 scheme uses that password string as-is as the PBKDF2 secret (saltsaltysalt, 1003 iters, 16-byte key, sha1). Decoding it derived a completely wrong key, corrupting the entire plaintext. Fixed on both the primary and fallback return paths (raw utf8 string instead of base64 decode).Bug B — unstripped 32-byte domain hash (
src/decryptor.ts)Chrome M130+ prepends a 32-byte
SHA-256(host_key)to the plaintext before encryption. After AES decrypt + PKCS7 unpad, those 32 bytes are now stripped — but only when they equalsha256(host_key). Older payloads without the prefix are left untouched, so the tool stays backward-compatible. This threadshost_keyintodecryptValue(encryptedValue, hostKey?)and updates the extractor call sites.Tests
tests/decryptor.test.tsto the corrected scheme (raw password string → PBKDF2).tsc --noEmitclean.Why
Unblocks authenticated
auth-curlusage (a login-gated watchtell alarm) —chrome-cookies --domain <logged-in domain> --curlnow emits printable-ASCII cookie values again.Notes
dist/is gitignored and rebuilt at publish time (prepublishOnly), so no compiled output is committed; the fix lives entirely insrc/.