Secret Scan and Rotation
Find committed credentials in a repository's working tree and full history, triage real secrets from test fixtures, and drive rotation-first remediation — with an absolute rule against ever printing a secret's actual value, even during the scan itself.
A secret deleted from the current commit is still live in every clone that already exists — removal without rotation is false comfort, and the scan that only checks the working tree misses exactly the leaks users are most surprised to learn about.
Who it's for: developers auditing a repository before making it public, security-conscious teams doing a pre-release credential sweep, anyone who just found a leaked API key and isn't sure what order to fix it in, engineers setting up secret-scanning prevention (pre-commit hooks, gitignore rules) for the first time
Example
"Check this repo for leaked secrets before we open-source it" → A full working-tree-and-history scan (not just the current files), each hit triaged as a real credential versus a test fixture with reasoning shown, a rotation-first remediation order for every real secret (revoke and rotate before touching the code), and a prevention setup — gitignore rules and a pre-commit hook — so the same leak class can't recur unnoticed
New here? 3-minute setup guide → | Already set up? Copy the template below.
# Secret Scan and Rotation
Find committed credentials in a repository and get them rotated and removed — without ever exposing them further yourself in the process.
**Absolute rule: never print a secret's actual value** — not in output, notes, todo items, commits, or PRs. Refer to every hit as `<kind> in <file>:<line> (commit <short-sha>)` and nothing more specific than that.
## Workflow
### 1. Check for a Scanning Tool
Check whether `gitleaks` (or an equivalent secret scanner) is available. If it's missing, don't skip the scan and don't stop the review — request the tool, and if it can't be installed, fall back to a manual scan and say explicitly in the report that the sweep was manual rather than tool-assisted.
### 2. Scan Both the Working Tree and Full History
History matters most: a secret deleted in the current HEAD is still live in every existing clone, and it's the hit users are most surprised to learn about.
**With a scanner available**, run a full-history detection scan and write the report to a JSON file for review.
**Without one**, do the same job by hand and say so in the final report:
- **Working tree**: grep for common secret patterns — API keys, tokens, passwords, private key headers, AWS access key IDs, Stripe-style secret keys, Slack-style tokens.
- **History, including files deleted since**: search the full commit history for known secret-prefix strings (not just the current tree), and separately look for files matching common credential filenames (`.env*`, `*credential*`, `*secret*`) that were deleted at some point — then read what those deleted files actually contained at the commit before their deletion.
- **Pipe anything read through a redactor before it ever reaches your own output or transcript** — replace any long alphanumeric run with a `[REDACTED]` placeholder. The no-printing rule holds even during your own investigation, not just in the final report.
### 3. Triage Each Hit
Read the context around every hit and classify it:
- **Real credential, test fixture, or example placeholder?** State which, and why — a string that matches a pattern isn't automatically a live secret.
- **For anything real**: what does it actually grant access to, and is it plausibly still valid (has enough time passed, or was the service since decommissioned)?
### 4. For Every Real Secret, in This Order
1. **Rotate first.** Tell the user exactly where to revoke or rotate it — the specific provider's console page or CLI command. Rotation beats removal: a history rewrite without rotation is false comfort, since anyone who already cloned the repo still has the old value.
2. **Remove it from the code.** Move it to environment variables or the project's existing secret-management approach — match however this codebase already handles configuration, rather than introducing a new pattern.
3. **Prevent recurrence.** Add or extend `.gitignore` for local secret files, and offer a scanner baseline config plus a pre-commit hook so the same class of leak can't happen again unnoticed.
4. **History purge is destructive and rewrites shared history.** Describe this trade-off explicitly and only proceed if the user explicitly asks for it — this step affects every existing clone and any open pull request built on the old history.
### 5. Deliver
A hit list (kind · location · verdict · rotation status), the cleanup branch or PR, and the prevention setup that was added or is being recommended.
## Tips
- Rotation is the step that actually matters; removal from the current tree without rotation is nearly worthless against anyone who already has a clone with the old history.
- When triaging, resist the urge to wave off a hit as "probably a test fixture" without actually reading the surrounding context — a real credential accidentally used as a "working example" in a test file is a genuinely common way leaks happen.
- Offer the pre-commit hook and `.gitignore` extension proactively, not just after being asked — preventing the next leak is as much the point as cleaning up the current one.
## Limitations
- History purges (rewriting git history to remove a secret from every past commit) are genuinely destructive to a shared repository — this only proceeds on explicit user request, never as a default action.
- A scanning tool catches known secret patterns and formats; a sufficiently obscure or custom credential format may need to be added to the scan patterns manually before it's caught.
- This finds and helps remediate committed secrets — it doesn't replace a real secret-management system (a vault, a cloud provider's secret manager) for how credentials should be handled going forward.
Get new playbooks like this one
One email a week with new Claude Code workflows. Free, like everything here.
No spam. Unsubscribe anytime.
What This Does
A tight, disciplined workflow for finding committed credentials and getting them safely remediated — scanning both the working tree and the full commit history, since a secret deleted from HEAD is still live in every clone that already exists, and it's the hit users are most surprised to learn about. Every real hit gets triaged in context (real credential, test fixture, or placeholder?) rather than flagged mechanically, and remediation follows a strict order: rotate first (tell the user exactly where to revoke it at the provider), then remove it from the code to match however the project already handles configuration, then add prevention (gitignore rules, a pre-commit hook) — with a destructive git-history purge only ever happening on explicit user request, described honestly as the trade-off it is.
The whole workflow runs under one absolute rule: never print a secret's actual value, not in output, notes, commits, or PRs — every hit is referred to only as its kind, file, line, and commit. When a dedicated scanning tool isn't available, the same job gets done by hand (pattern-matching the working tree and history, reading deleted credential files at the commit before their deletion) with every read piped through a redactor before it reaches the agent's own output — the no-printing rule holds during the investigation itself, not just in the final report.
Quick Start
Step 1: Create a Project Folder
mkdir secret-scan && cd secret-scan
Step 2: Download the Template
Click Download above, then:
mv ~/Downloads/CLAUDE.md ./
Step 3: Run a Scan
claude
Point Claude at the repository and ask it to scan for committed secrets. It will check for a scanning tool, sweep both the working tree and full history, triage each hit, and walk through rotation-first remediation for anything real.
Tips & Best Practices
- Rotation is the step that actually matters — removal from the current tree without rotation is nearly worthless against anyone who already has a clone with the old history.
- When triaging, resist waving off a hit as "probably a test fixture" without reading the surrounding context — a real credential accidentally used as a "working example" in a test file is a genuinely common way leaks happen.
- Offer the pre-commit hook and gitignore extension proactively, not just after being asked — preventing the next leak is as much the point as cleaning up the current one.
Limitations
- History purges (rewriting git history to remove a secret from every past commit) are genuinely destructive to a shared repository — this only proceeds on explicit user request, never as a default action.
- A scanning tool catches known secret patterns and formats; a sufficiently obscure or custom credential format may need to be added to the scan patterns manually before it's caught.
- Finds and helps remediate committed secrets — it doesn't replace a real secret-management system (a vault, a cloud provider's secret manager) for how credentials should be handled going forward.