secrets-scan

Caution

Secrets committed to git are permanent — even after deletion. A single password=prod123 in a config file, a hardcoded AWS key in a test fixture, a connection string left in a migration script. Once pushed, the history retains it. /brewtools:secrets-scan finds these before they become incidents.

Tip

10 parallel agents, one command. The skill splits your git file list into 10 chunks, runs haiku agents in parallel, merges results, ranks by severity, and writes a structured report — all without leaving your Claude session. Add --fix to remediate interactively.

Quick reference

FieldValue
Command/brewtools:secrets-scan
Arguments[--fix] — no args = scan only, --fix = interactive remediation
Modelsonnet
Contextsession
ToolsRead, Task, Write, Bash, AskUserQuestion

When to use

  • Pre-push audit — run before opening a PR or pushing to a remote branch
  • Open-source prep — before making a private repo public, scan the full history surface
  • CI gate — catch secrets that slipped past .gitignore rules
  • Post-incident — verify no additional credentials are exposed after a breach
  • Onboarding — audit a legacy codebase you’ve just inherited

Examples

# Scan only — full repo, severity-ranked report
/brewtools:secrets-scan

# Scan and remediate interactively (CRITICAL + HIGH findings prompted)
/brewtools:secrets-scan --fix

# Free-form intent after the command (the skill is user-invoked only)
/brewtools:secrets-scan check for secrets before I open-source this repo

Expected output after scan:

## Secrets Scan Complete — FINDINGS

| Metric    | Value |
|-----------|-------|
| Files     | 342   |
| Unscanned | 0     |
| CRITICAL  | 1     |
| HIGH      | 3     |
| MEDIUM    | 7     |
| LOW       | 12    |

Report: .claude/reports/20260417-143022_secrets-scan/report.md (mode 600)

Verdict is one of CLEAN, FINDINGS, or INCOMPLETE — never CLEAN while any chunk failed reconciliation.

Flow

  1. Setup

    Verifies the working directory is a git repository, then builds the scan list from git ls-files and filters it: binary and media extensions (images, fonts, archives, jars, compiled objects, minified bundles, source maps), vendor and build directories (node_modules, vendor, dist, build, target, pycache, Pods, …) and lock files are dropped before anything is chunked. Creates a timestamped report directory under .claude/reports/ (chmod 700) and appends .claude/reports/ to .gitignore when nothing already ignores it — a report that names where credentials live must never become committable.

  2. Split & launch 10 agents

    Divides the file list into 10 equal chunks (ceil division). Spawns 10 general-purpose haiku agents in a single parallel Task call — each agent reads its assigned files and applies detection patterns.

  3. Reconcile & merge

    Checks each agent’s response against its assigned file list — scanned[] + skipped[] must cover exactly the files it was given. A mismatched or malformed chunk is re-spawned once with the identical prompt; still wrong after that, it is recorded UNSCANNED and the scan can no longer be reported clean. Reconciled chunks are then deduplicated by path+line, merged, and sorted: CRITICAL → HIGH → MEDIUM → LOW.

  4. Generate report

    Writes {DIR}/report.md (chmod 600) with a verdict (CLEAN / FINDINGS / INCOMPLETE), a summary table, per-severity finding tables — file, line, category, value length, a sha256[:12] fingerprint, a masked preview, description — per-agent stats, an unscanned section when a chunk failed twice, and a full file inventory including skipped files with skip reasons.

  5. Display summary

    Prints a compact table of the verdict and severity counts plus the report path directly in the session. No need to open the file to see the headline result.

  6. Fix mode

    Triggered by —fix flag or automatically when CRITICAL/HIGH findings exist. Walks through each finding with AskUserQuestion: fix inline, move to env var, add file to .gitignore, mark as false positive, or skip.

Delegation

Warning

A big task handed to one agent = an agent gone for an hour. You cannot observe it, you cannot correct it, and it usually drifts off-target. Here the 10-way split is the sizing rule: one subagent = ONE chunk, ~10 steps. A repo big enough that a chunk still exceeds that gets more chunks, not bigger ones — and every Task call goes out in one message.

Each chunk agent receives the same six-field brief, reused verbatim per chunk:

FieldContent
GOALaudit the repo for leaked credentials before they reach a remote
ROLEread and classify only — no edit, delete, redact, or rewrite
SCOPEexactly the listed files; out — every other path, git history, .git/
CONTEXTthe file list was produced and filtered in Phase 1 — do not re-discover or re-filter it; nine siblings scan the other chunks right now
CONSUMERthe skill reconciles each agent’s scanned[] + skipped[] against its assigned file list before merging — a mismatched or malformed chunk is re-spawned once, and still-wrong is reported UNSCANNED, never merged in silently
DONEthe specified JSON object, nothing else — no prose, no markdown fence

A bare one-line task is never enough. The failure mode is concrete: a malformed or chatty response used to silently remove an entire chunk from the merged report, and a missed CRITICAL there is a credential shipped to a remote. Reconciliation is what closes that gap — the chunk either gets accounted for or the whole scan is marked INCOMPLETE.

The CONTEXT line has to be true. The brief tells each agent the list is already filtered and instructs it not to skip anything — so when Phase 1 handed over an unfiltered git ls-files, ten agents spent their chunk budget reading .png, .jar, lockfiles and vendored code they had been told not to skip. Phase 1 now filters for real.

Redaction is mandatory, not optional. Agents never quote, echo, or summarise a matched value — for every hit they run the skill’s redaction script and copy back only a length, a sha256[:12] fingerprint, and a preview of at most 4 leading characters. The raw secret never enters an agent’s response, the report, or this chat.

Detection rules

What gets flagged:

CategoryPatterns
Passwordspassword, passwd, secret, pwd followed by = or : and a value
API keysapi_key, access_key, apikey, api_secret
Tokenstoken, bearer, auth_token, access_token
AWS credentialsAKIA[0-9A-Z]{16}, aws_secret, aws_access_key
Database URLsJDBC, MongoDB, MySQL, PostgreSQL connection strings with embedded credentials
Private keys-----BEGIN ... PRIVATE KEY-----, client_secret, encryption_key

Severity levels:

LevelCriteria
CRITICALReal credentials, private keys, database connection strings with passwords
HIGHReal API keys or tokens, AWS credentials
MEDIUMSuspicious hardcoded values that may be secrets
LOWPlaceholder values (changeme, YOUR_KEY, xxx, dummy)

Automatically skipped:

Environment variable references (process.env.*, ${VAR}, os.getenv()), common placeholders, documentation comments, binary files.

Fix mode options:

OptionAction
FixDelete or replace the secret inline
Move to env varExtract value into an environment variable reference
Add to .gitignoreAppend the file path to .gitignore
Mark false positiveAcknowledge and skip — logged in report
SkipLeave as-is, move to next finding
🚀

Deploy skill

Ship changes via GitHub Actions workflows and GHCR — pair with a clean secrets audit before release.

🔗

GitHub source

Source code, detection patterns, and agent prompt templates.

📄

Brewtools overview

All brewtools skills — text optimization, SSH management, plugin updates, and more.

Updating plugins

Use /brewtools:plugin-update to check and update the brewcode plugin suite in one command. See the FAQ for details.