moonD4rk/HackBrowserData · error
encrypted_key unexpected prefix: got %q, want %q
Error message
encrypted_key unexpected prefix: got %q, want %q
What it means
Chrome's os_crypt.encrypted_key blob is defined as the ASCII string 'DPAPI' followed by a DPAPI-protected blob. RetrieveKey checks this magic prefix after base64 decoding and errors if the first 5 bytes differ, because the remaining bytes are about to be handed to DecryptDPAPI and would be meaningless without it.
Source
Thrown at masterkey/retriever_windows.go:39
return nil, fmt.Errorf("read Local State: %w", err)
}
encryptedKey := gjson.GetBytes(data, "os_crypt.encrypted_key")
if !encryptedKey.Exists() {
return nil, fmt.Errorf("os_crypt.encrypted_key not found in Local State")
}
keyBytes, err := base64.StdEncoding.DecodeString(encryptedKey.String())
if err != nil {
return nil, fmt.Errorf("base64 decode encrypted_key: %w", err)
}
const dpapiPrefix = "DPAPI"
if len(keyBytes) <= len(dpapiPrefix) {
return nil, fmt.Errorf("encrypted_key too short: %d bytes", len(keyBytes))
}
if string(keyBytes[:len(dpapiPrefix)]) != dpapiPrefix {
return nil, fmt.Errorf("encrypted_key unexpected prefix: got %q, want %q", keyBytes[:len(dpapiPrefix)], dpapiPrefix)
}
masterKey, err := crypto.DecryptDPAPI(keyBytes[len(dpapiPrefix):])
if err != nil {
return nil, fmt.Errorf("DPAPI decrypt: %w", err)
}
return masterKey, nil
}
// DefaultRetrievers wires the Windows tiers: DPAPI for v10, ABE for v20 (Chrome 127+, via reflective
// injection). Both run — a profile upgraded from pre-v127 mixes v10+v20 and needs both (issue #578).
func DefaultRetrievers() Retrievers {
return Retrievers{
V10: &DPAPIRetriever{},
V20: &ABERetriever{},
}
}
View on GitHub (pinned to 0503d04d7a)
Solutions
- Confirm hints.LocalStatePath points to a Chromium-based browser's profile 'Local State' file (Chrome/Edge/Brave), not a Firefox profile.
- Verify the field is os_crypt.encrypted_key — do not pass cookie ciphertext or other blobs here.
- Check whether the target browser is an unusual Chromium fork with a different os_crypt scheme and route it accordingly.
- If the field is genuinely corrupt, re-launch the browser to regenerate it.
Example fix
// before: assuming any blob is a DPAPI key
masterKey, err := crypto.DecryptDPAPI(keyBytes)
// after: verify the magic prefix first
if !bytes.HasPrefix(keyBytes, []byte("DPAPI")) {
return nil, fmt.Errorf("not a DPAPI key blob")
}
masterKey, err := crypto.DecryptDPAPI(keyBytes[5:]) Defensive patterns
Strategy: validation
Validate before calling
raw, _ := base64.StdEncoding.DecodeString(encKey)
if !bytes.HasPrefix(raw, []byte("DPAPI")) {
return errors.New("not a Chromium os_crypt DPAPI key blob")
} Type guard
func isChromiumEncryptedKey(b []byte) bool { return bytes.HasPrefix(b, []byte("DPAPI")) } Try / catch
key, err := retriever.RetrieveKey(hints)
if err != nil && strings.Contains(err.Error(), "unexpected prefix") {
// wrong browser/format; route to the correct retriever
} Prevention
- Only feed os_crypt.encrypted_key into DPAPI retrieval — never cookie ciphertext.
- Identify browser family (Chromium vs Firefox) before retrieval.
- Verify with jq that you read the intended JSON path.
When it happens
Trigger: The decoded encrypted_key is longer than 5 bytes but does not start with the literal bytes 'DPAPI' — i.e. it is not a Chrome DPAPI key blob.
Common situations: Pointing at a Firefox/Gecko-based browser's key file or a non-Chromium browser with a different key format; a Chromium fork that changed the prefix; decrypting a value that is actually an AES-GCM v10 cookie ciphertext rather than the master key; hand-crafted test data.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- encrypted_key too short: %d bytes
- base64 decode encrypted_key: %w
- DPAPI not supported on this platform
- abe: encrypted key too short: %d bytes
- abe: unexpected prefix: got %q, want %q
AI-assisted analysis of moonD4rk/HackBrowserData@0503d04d7a (2026-09-06).
Data as JSON: /api/errors/ed17955f89d2aa96.
Report an issue: GitHub.