moonD4rk/HackBrowserData · error

DPAPI decrypt: %w

Error message

DPAPI decrypt: %w

What it means

This wraps a failure from crypto.DecryptDPAPI, which calls the Windows DPAPI CryptUnprotectData API on the bytes following the 'DPAPI' prefix. DPAPI only succeeds when the blob was protected under the same Windows user (and, for machine-scope, the same machine), so failure means the master key could not be decrypted in this context.

Source

Thrown at masterkey/retriever_windows.go:44

		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

  1. Run the tool as the same Windows user account that owns the browser profile (impersonate or log in as that user).
  2. Use machine-context DPAPI recovery options or the user's password via DPAPI backup-key recovery when off-box analysis is required.
  3. Re-open the browser on the original machine/user so Chrome can regenerate a decryptable key (existing saved data re-encrypts on next use).
  4. If corrupt-blob is suspected, replace the Local State with a fresh one from a healthy profile of the same user.
  5. For Chrome 127+ v20 cookies, ensure the ABE retriever is used — DPAPI v10 keys will not decrypt v20 payloads.

Example fix

// before: running as service account, DPAPI fails silently in context
key, err := retriever.RetrieveKey(hints)
// after: verify same-user context before calling
if cur, _ := user.Current(); cur.Username != profileOwner {
	return nil, fmt.Errorf("must run as %s for DPAPI decrypt", profileOwner)
}
key, err := retriever.RetrieveKey(hints)
Defensive patterns

Strategy: try-catch

Validate before calling

// Precondition checks possible before the call:
if runtime.GOOS != "windows" { return errors.New("DPAPI requires Windows") }
if cur, _ := user.Current(); cur.Username != expectedOwner {
	return fmt.Errorf("run as profile owner %s", expectedOwner)
}

Try / catch

key, err := retriever.RetrieveKey(hints)
if err != nil && strings.Contains(err.Error(), "DPAPI decrypt") {
	// impersonate profile owner or fall back to ABE retriever for v20
}

Prevention

When it happens

Trigger: DecryptDPAPI returned an error from CryptUnprotectData: running as a different Windows user than the one whose profile is being read; the Local State was copied from another machine; the DPAPI blob is corrupt; roaming-profile/credential-restore issues broke the master key.

Common situations: Security tool run via SSH, a service account, or an elevated process with a different logon session than the browser's; analyzing a copied-off profile on another machine; browser profile migrated between machines; corrupted Local State after a crash.

Related errors


AI-assisted analysis of moonD4rk/HackBrowserData@0503d04d7a (2026-09-06). Data as JSON: /api/errors/9df1db28accd8a86. Report an issue: GitHub.