moonD4rk/HackBrowserData · error

security command: %w (%s)

Error message

security command: %w (%s)

What it means

The `security` command exited non-zero with non-empty stderr; the exec error and the captured stderr text are wrapped as "security command: %w (%s)" so the OS-level diagnostic (e.g. "SecKeychainSearchCopyNext: The specified item could not be found in the keychain") is preserved alongside the exit status.

Source

Thrown at masterkey/retriever_darwin.go:148

	ctx, cancel := context.WithTimeout(context.Background(), securityCmdTimeout)
	defer cancel()

	var stdout, stderr bytes.Buffer
	cmd := exec.CommandContext(ctx, "security", "find-generic-password", "-wa", strings.TrimSpace(storage)) //nolint:gosec
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	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 {

View on GitHub (pinned to 0503d04d7a)

Solutions

  1. Read the stderr text in the parentheses — it contains the specific `security` diagnostic
  2. If it says the item could not be found, verify the storage/service name with `security dump-keychain`
  3. Check spelling of the account passed via -wa against actual keychain records
  4. If the item truly is absent, handle via errors.Is(errStorageNotFound) fallback rather than retrying

Example fix

// before
key, err := r.RetrieveKey(hints)
return key, err
// after
key, err := r.RetrieveKey(hints)
if err != nil && strings.Contains(err.Error(), "could not be found") {
	log.Warnf("keychain item %q missing: %v", hints.Storage, err)
}
return key, err
Defensive patterns

Strategy: try-catch

Validate before calling

out, err := exec.Command("security", "find-generic-password", "-a", storage).CombinedOutput()
if err != nil {
	return fmt.Errorf("pre-check failed: %s", out)
}

Type guard

func isItemMissing(err error) bool {
	return err != nil && strings.Contains(err.Error(), "could not be found")
}

Try / catch

key, err := r.RetrieveKey(hints)
if err != nil {
	var secErr *exec.ExitError
	if errors.As(err, &secErr) {
		log.Printf("security stderr: %s", secErr.Stderr)
	}
}

Prevention

When it happens

Trigger: cmd.Run() fails, ctx deadline not exceeded, and stderr contains text — the retriever surfaces both the exit error and stderr contents from `security find-generic-password`.

Common situations: The requested generic-password item doesn't exist (item not found message), the service/account name was misspelled, or keychain-level errors printed by `security`.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


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