moonD4rk/HackBrowserData · warning

security command timed out after %s

Error message

security command timed out after %s

What it means

The retriever shells out to `security find-generic-password -wa <storage>` with a context deadline; when cmd.Run fails because the context deadline was exceeded, it returns "security command timed out after %s" with the timeout duration. This replaces the raw context error with an actionable message.

Source

Thrown at masterkey/retriever_darwin.go:140

	}

	key, err := r.retrieveKeyOnce(storage)
	r.cache[storage] = securityResult{key: key, err: err}
	return key, err
}

func (r *SecurityCmdRetriever) retrieveKeyOnce(storage string) ([]byte, error) {
	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)
	}

View on GitHub (pinned to 0503d04d7a)

Solutions

  1. Re-run interactively and accept the keychain access prompt for the calling binary
  2. Pre-authorize the tool in Keychain Access (Access Control tab) so no prompt appears
  3. Increase the deadline in the context passed to the retriever if the timeout is too short
  4. Use the KeychainPasswordRetriever instead, which unlocks the keychain directly without prompting

Example fix

// before
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
// after
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
Defensive patterns

Strategy: retry

Validate before calling

if _, err := exec.LookPath("security"); err != nil {
	return errors.New("security CLI not available")
}
if deadline, ok := ctx.Deadline(); ok && time.Until(deadline) < 5*time.Second {
	return errors.New("context deadline too short for keychain prompt")
}

Type guard

func isSecurityTimeout(err error) bool {
	return err != nil && strings.Contains(err.Error(), "timed out after")
}

Try / catch

key, err := r.RetrieveKey(hints)
if err != nil && strings.Contains(err.Error(), "security command timed out") {
	// prompt was likely unanswered; retry with longer deadline or password retriever
	key, err = passwordRetriever.RetrieveKey(hints)
}

Prevention

When it happens

Trigger: retrieveKeyOnce invoked with a context whose deadline elapses before the `security` command finishes; the keychain access prompt is shown and unanswered until the timeout fires.

Common situations: The user ignored or never saw the macOS keychain-access permission dialog, a headless/SSH session where the dialog can't be rendered, or an unusually slow system.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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