moonD4rk/HackBrowserData · error
keychain: empty secret for %s
Error message
keychain: empty secret for %s
What it means
After `security find-generic-password` succeeds with no stderr, the library reads the printed password from stdout. If stdout is empty (or whitespace only), there is no safe-storage secret to derive the V10 key from, so it fails naming the storage label that had no secret.
Source
Thrown at masterkey/retriever_darwin.go:156
if err := cmd.Run(); err != nil {
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
return nil, fmt.Errorf("security command timed out after %s", securityCmdTimeout)
}
// `security` exits non-zero with empty stderr when the user denies the prompt or mistypes;
// surface that instead of the cryptic "exit status 128 ()".
stderrStr := strings.TrimSpace(stderr.String())
if stderrStr == "" {
return nil, fmt.Errorf("security command: %w (likely keychain access denied or wrong password)", err)
}
return nil, fmt.Errorf("security command: %w (%s)", err, stderrStr)
}
if stderr.Len() > 0 {
return nil, fmt.Errorf("keychain: %s", strings.TrimSpace(stderr.String()))
}
secret := bytes.TrimSpace(stdout.Bytes())
if len(secret) == 0 {
return nil, fmt.Errorf("keychain: empty secret for %s", storage)
}
return darwinParams.deriveKey(secret), nil
}
// DefaultRetrievers wires the macOS V10 chain (the only tier Chromium uses here), first success wins:
// 1. GcoredumpRetriever — CVE-2025-24204 exploit (root only)
// 2. KeychainPasswordRetriever — direct unlock, skipped when password is empty
// 3. SecurityCmdRetriever — `security` CLI fallback (may prompt)
func DefaultRetrievers(keychainPassword string) Retrievers {
chain := []Retriever{&GcoredumpRetriever{}}
if keychainPassword != "" {
chain = append(chain, &KeychainPasswordRetriever{Password: keychainPassword})
}
chain = append(chain, &SecurityCmdRetriever{cache: make(map[string]securityResult)})
return Retrievers{V10: NewChain(chain...)}
}
View on GitHub (pinned to 0503d04d7a)
Solutions
- Open Keychain Access, find the '<Browser> Safe Storage' item, and confirm its password attribute is non-empty (click 'Show password')
- Re-save the secret: use the browser once (visit a site, save a password/cookie) so Chromium repopulates Safe Storage, then retry
- Manually create the entry: security add-generic-password -a 'Chrome Safe Storage' -s 'Chrome Safe Storage' -w '<secret>'
- Rely on a different tier: supply the login keychain password (KeychainPasswordRetriever) or run as root (GcoredumpRetriever)
Defensive patterns
Strategy: validation
Validate before calling
out, err := exec.Command("security", "find-generic-password", "-wa", "Chrome Safe Storage").Output()
if err == nil && len(bytes.TrimSpace(out)) == 0 {
// empty secret — Safe Storage entry has no password; skip this tier
} Prevention
- Inspect the '<Browser> Safe Storage' item in Keychain Access and confirm a non-empty password before running extraction
- Use the browser at least once on the target profile so Chromium materializes Safe Storage with real data
- Recreate the entry with `security add-generic-password` if it was blanked
- Configure the full retriever chain so an empty secret falls through to the password/root tiers
When it happens
Trigger: `security find-generic-password -wa <storage>` exits 0, prints nothing to stderr, but also no password data — typically when the generic-password item exists but has an empty password attribute, or `-w` matching yields no value.
Common situations: Chromium installed but never saved cookies/passwords so Safe Storage was created empty; user deleted the secret body from Keychain Access; a third-party keychain entry with the right label but blank password.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- requires root privileges
- keychain gcore dump not built in (rebuild with -tags keychai
- not found in credential store
- read keychain: %w
- tried %d candidates, none unlocked keychain
AI-assisted analysis of moonD4rk/HackBrowserData@0503d04d7a (2026-09-06).
Data as JSON: /api/errors/0995fa3c67cdc128.
Report an issue: GitHub.