Skip to content

Secret scanner

Muhammet Şafak edited this page Jun 1, 2026 · 3 revisions

Home / Operations / Secret scanner

Secret scanner

Pre-send guard that flags credential-shaped strings in the diff before the LLM call. Prevents accidental upload of API keys, private keys, tokens, etc. to a third-party provider.

What it scans

The scanner walks two surfaces:

  1. The diff — only added lines (+-prefixed, excluding the +++ b/path header). Removed and context lines are skipped — the goal is to catch new leaks, not re-flag history that is already on disk somewhere.
  2. User-authored rules content — any non-default COMMITBRIEF.md or OUTPUT.md you have written. These join the system prompt verbatim, so a credential pasted into either file would leak just as surely as one in the diff (UC-05). Embedded defaults are presumed clean and skipped.

Patterns matched

Hardcoded regex list in internal/guard/secrets.go. As of v1.0.0:

Name Pattern (regex) Notes
AWS Access Key AKIA[0-9A-Z]{16} AWS access-key-ID prefix.
GitHub Token gh[pousr]_[A-Za-z0-9]{36,} Classic / fine-grained / OAuth tokens (any prefix from the GH set).
GitLab Token glpat-[A-Za-z0-9_-]{20,} Personal access tokens.
Anthropic API Key sk-ant-[A-Za-z0-9_-]{40,} Console.anthropic.com keys.
OpenAI API Key sk-(?:proj-|live-)?[A-Za-z0-9]{40,} Including project + live variants.
JWT eyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,} Three-segment base64url-style JWT.
Stripe Live Key sk_live_[A-Za-z0-9]{24,} Production Stripe secret key prefix.
PEM Private Key -----BEGIN [A-Z ]*PRIVATE KEY----- Any PEM private-key header (RSA / EC / OPENSSH / generic).

Pattern names are sortable via the guard.SecretPatternNames() helper — useful if you want to audit the set from a test.

What the user sees

When the scanner hits, stderr shows:

⚠  Possible secrets detected in diff (2 line(s)):
   line 42: AWS Access Key
   line 87: GitHub Token, OpenAI API Key

Send to LLM anyway?

  Yes  ▸ No        (←/→ to choose · Enter to confirm)

On a TTY the confirmation is an arrow-key Yes/No toggle (huh), pre-selected on No. Piped/non-TTY input falls back to the typed y/N line (a non-TTY run aborts unless --allow-secrets is set).

Important

The matched substring is never printed — only line numbers and pattern names. This keeps the secret out of stderr (and any CI log that captures it) even when the scanner fires.

Behavior matrix

Context Outcome
TTY, no --allow-secrets, no --yes Prompt; default no → abort with aborted: pre-send secret scanner.
TTY, --yes Prompt still shows. --yes does NOT bypass the scanner since v0.9.1 (UC-01).
Non-TTY, no --allow-secrets Abort with Aborted (non-interactive); pass --allow-secrets to override.
Any context, --allow-secrets Skip the scanner entirely.
guard.secret_scan: false in config Skip the scanner entirely (whole-binary opt-out).

The matched-line list is still printed to stderr in the --allow-secrets case — you opted in, but you still see what was flagged.

Disabling

Per-invocation

commitbrief --staged --allow-secrets

Per-config (whole binary)

commitbrief config set guard.secret_scan false

This is appropriate if you have a separate secrets-management layer (gitleaks, trufflehog, pre-commit hooks) doing the same job and the prompt is just noise.

What CommitBrief does NOT do here

  • It does NOT scan for entropy-based detections (high-entropy random-looking strings). Pure pattern matching only.
  • It does NOT scan for service-specific tokens not on the list above (Slack tokens, Twilio SIDs, etc.). PRs to add new patterns are welcome.
  • It does NOT auto-redact. The scanner only abort/prompts; it never rewrites the diff.
  • It does NOT scan removed-line history. A pre-existing checked-in key remains until you rotate it (which you should).

See also

Clone this wiki locally