Skip to content

Secret scanner

Muhammet Şafak edited this page Jun 19, 2026 · 4 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.

Adding your own patterns (guard.secret_patterns)

Since v1.7.0 (ADR-0024) you can extend the built-in list with your own credential regexes in config — useful for internal or company-specific token formats:

guard:
  secret_patterns:
    - name: Internal Token
      regex: 'INTERNAL-[A-Z0-9]{10}'
    - name: Acme API Key
      regex: 'acme_(live|test)_[A-Za-z0-9]{32}'
  • Additive only. User patterns run alongside the built-ins; they cannot disable or shadow one. A user entry whose name collides with a built-in is ignored (the built-in wins). To turn the scanner off entirely, use guard.secret_scan: false.
  • Each regex is a Go regexp (RE2) expression. An invalid pattern aborts the review before any provider call, naming the offending entry.
  • As with the built-ins, only the line number and pattern name are reported — never the matched text.
  • commitbrief config get guard.secret_patterns lists the configured names. config set is rejected for this key (it is a list of objects) — edit the config file directly, like providers.*.pricing.*.

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 ship built-in patterns for every service-specific token (Slack tokens, Twilio SIDs, etc.). Add them yourself via guard.secret_patterns, or open a PR to add a common one to the built-in set.
  • 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