🚨 STOP. Do these 3 things RIGHT NOW:
- Revoke the token. npm:
npm token revoke <token-id>/ GitHub: github.com/settings/tokens > Delete / AWS:aws iam deactivate-access-key --access-key-id <key>- Assume everything the token could access is compromised.
- Do NOT delete logs, force-push, or post about it publicly yet.
Done? Now read on.
TL;DR — Attackers harvest leaked credentials from public repos within 5 minutes. You have one hour before the damage compounds. This runbook walks through revocation, blast radius scoping, downstream rotation, forensics, and hardening, with exact commands for npm, GitHub, Vercel, and AWS. Jump to Minute 0-5 →
📊 The gap that kills you:
- Bots scan GitHub for leaked keys within 5 minutes of exposure
- Average team takes 94 days to notice a leaked secret
- Credential breaches take 292 days to resolve on average
- 53% of all data breaches involve stolen credentials
You just got a GitHub notification that your npm token was found in a public commit. Or you ran git log and saw your AWS key in plaintext. Or GitHub Secret Scanning just emailed you.
Your heart rate spikes. That’s normal.
What you do in the next 60 minutes determines whether this is a 1-hour inconvenience or a 1-week incident. I’ve been through this twice. The first time I panicked and force-pushed. It made everything worse. The second time I followed this runbook. Contained in 45 minutes.
Here’s the runbook.
What should you do in Minute 0-5? (Revoke the token)
Revoke the leaked token immediately. Don’t scope the damage first. Don’t investigate how it happened. Don’t try to clean git history. Revoke. Every minute the token is live, automated scanners can use it. Threat actors harvest credentials from public repos within 5 minutes of exposure (DevActivity/GitHub, 2026).
One command per platform:
npm
# List your tokens to find the leaked onenpm token list
# Revoke itnpm token revoke <token-id>GitHub PAT
# Via CLI (if you have gh installed)gh auth token # shows current token# Then go to github.com/settings/tokens > Delete the compromised token
# Or via API (for fine-grained tokens)gh api -X DELETE /user/tokens/<token-id>For GitHub OAuth and App credentials, use the Credential Revocation API (GA since March 2026).
AWS
# Deactivate first, then deleteaws iam deactivate-access-key --access-key-id AKIA...aws iam delete-access-key --access-key-id AKIA...Vercel
Project Settings > Environment Variables > click the variable > Regenerate. Or via CLI:
vercel env rm <VAR_NAME> productionvercel env add <VAR_NAME> productionGCP
gcloud iam service-accounts keys delete <key-id> \ --iam-account=<service-account-email>If you’re reading this at 2am because GitHub just emailed you, start here. Copy the command. Run it. Then breathe.
Key insight: Threat actors harvest IAM credentials from public repos within 5 minutes of exposure, while the average team takes 94 days to notice a leaked secret (Verizon DBIR, 2025). The gap between 5 minutes and 94 days is where breaches happen. Revoking in Minute 0 closes that gap.
What should you do in Minute 5-15? (Scope the blast radius)
Now that the token is revoked, figure out what it could have accessed. The blast radius depends on three things: the token type, its scopes/permissions, and how long it was exposed. A classic GitHub PAT with repo scope and no expiration is worst-case: full read/write to every repo, including private ones.
| Token type | Blast radius | Worst-case access |
|---|---|---|
| npm publish token | Your packages | Attacker publishes malicious versions |
| npm read-only token | Package metadata | Low risk, but rotate anyway |
| GitHub classic PAT (repo) | All repos, including private | Source code, secrets in code, CI configs |
| GitHub fine-grained PAT | Scoped repos only | Limited to selected repos |
| AWS IAM access key | Depends on IAM policy | Could be everything in your AWS account |
| Vercel env var | One project’s secrets | API keys, DB credentials, OAuth tokens |
How to check what was accessed
GitHub: Check your security log for the exposure window:
# For personal accounts# Settings > Security log > filter by date range
# For org accounts (if you have admin access)gh api "/orgs/{org}/audit-log?phrase=action:oauth_authorization.create"AWS CloudTrail: Query access events for the compromised key:
aws cloudtrail lookup-events \ --lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIA... \ --start-time 2026-04-28T00:00:00Z \ --end-time 2026-04-30T23:59:59ZExposure window: When was the token committed? (git log --all --oneline | head -20 to find the commit). When did you revoke it? That gap is your compromise window. Everything accessed during that window is potentially compromised.
Key insight: Stolen credentials drive 22% of all security incidents and take an average of 292 days to resolve, making them the most time-consuming breach category (IBM/Deepstrike, 2025). Scoping the blast radius in Minute 5-15 prevents the 292-day tail.
What should you do in Minute 15-30? (Rotate everything downstream)
The leaked token is dead. But if it accessed other secrets, those secrets are now compromised too. This is the cascade that turns a 1-hour incident into a 1-week incident. Rotate every credential the leaked token could have reached.
The cascade checklist
CI/CD secrets (check these first):
# GitHub Actions secrets - regenerate via web UI# Settings > Secrets and variables > Actions > Update each secret
# Vercel env varsvercel env ls production# Regenerate any that the leaked token could have readnpm publish tokens: If the leaked credential could read your CI environment (e.g., a GitHub PAT with repo access to a project that stores npm tokens in GitHub Actions secrets), your publish token is compromised.
npm token revoke <publish-token-id>npm token create --cidr=<your-ci-ip-range>Database credentials: If any environment variable contained DB connection strings, rotate those at the database level. Don’t just update the env var.
OAuth tokens: If the leaked token had access to Vercel environment variables that contained Google or Slack OAuth tokens, treat those as compromised too. Run the OAuth permissions audit from our Level 3 post.
SSH keys: If the compromised environment had ~/.ssh/ accessible:
# Generate new keyssh-keygen -t ed25519 -C "your_email@example.com"
# Add to GitHubgh ssh-key add ~/.ssh/id_ed25519.pub --title "rotated-$(date +%Y%m%d)"Solo devs: this is 5-10 secrets max. Team leads: multiply by the number of services your CI pipeline touches. Start a shared doc and check things off.
Key insight: 53% of all data breaches involve stolen credentials, and the average cost of a credential-related breach is $4.44 million (IBM Cost of a Data Breach / Deepstrike, 2025). The cascade from one leaked token to downstream credentials is what drives these costs. Cutting the cascade at Minute 15 is the highest-ROI action in this runbook.
What should you do in Minute 30-45? (Export logs before they rotate)
Export audit logs NOW, before the platforms rotate them. GitHub retains security events for 90 days. AWS CloudTrail retains for 90 days by default. npm audit logs are limited. If you don’t export now, you lose the forensic evidence you need for the post-mortem.
Log export checklist
| Platform | What to export | How | Retention |
|---|---|---|---|
| GitHub | Security log | Settings > Security log > Export | 90 days |
| AWS | CloudTrail events | aws cloudtrail lookup-events (see above) | 90 days default |
| Vercel | Deployment logs | Dashboard > Deployments > filter by date | 30 days |
| npm | Token last-used | npmjs.com/settings/~/tokens | Limited |
What to look for in the logs:
- Access from unfamiliar IPs or geolocations
- New tokens created during the exposure window
- Packages published (for npm tokens)
- Repository clones or API access outside normal patterns
- New SSH keys added to your account
Get weekly security tips for AI coders. Hooks, credential hygiene, and real breach breakdowns. One email per week. Subscribe to AI Developer Weekly →
Key insight: The average team takes 94 days to notice a leaked secret (Verizon DBIR, 2025). Exporting logs in Minute 30-45 ensures you have forensic evidence even if the exposure happened weeks ago. Platforms delete logs on their own schedule, not yours.
What should you do in Minute 45-60? (Harden for next time)
The fire is out. Now prevent the next one. Three changes that take 15 minutes total eliminate the most common credential leak vectors. GitHub Push Protection alone blocks 39 token types before they reach a repo (GitHub Docs, 2026), and fine-grained tokens with 90-day expiration close the classic PAT exposure window that enabled the axios breach.
1. Enable GitHub Push Protection (free for public repos):
# Check if secret scanning is enabledgh api /repos/{owner}/{repo} --jq '.security_and_analysis'Push Protection blocks 39 token types before they reach the repo. It won’t catch custom secrets, but it catches npm, AWS, GCP, Stripe, and most major providers (GitHub Docs, 2026).
2. Switch to fine-grained GitHub tokens with 90-day expiration. Classic PATs never expire by default. Fine-grained tokens expire, scope to specific repos, and support IP restrictions.
3. Layer your defenses with the supply chain series:
| Level | Defense | Post |
|---|---|---|
| 1 | .npmrc hardening | The 30-Second npm Defense |
| 2 | PreToolUse hooks | Stop npm Attacks with Hooks |
| 3 | OAuth audit + scope hygiene | OAuth Supply Chain Defense |
| 4 | Incident response (this post) | You’re here |
What are the 5 panic moves that make a token leak worse?
The worst thing you can do after a credential leak is panic and compound the damage. Credential-related breaches already take 292 days to resolve on average (IBM/Deepstrike, 2025). These 5 anti-patterns add weeks on top of that by destroying evidence, alerting attackers, or delaying team response.
| Anti-pattern | Why it’s worse | Do this instead |
|---|---|---|
| Force-pushing to delete the commit | Token is already in GitHub event log and bot caches. Force-push destroys your audit trail. | Revoke the token first. Clean history later with git filter-repo. |
| Deleting the repo | Commit was already scraped by bots. Now you’ve lost code AND logs. | Revoke, export logs, then clean history. |
| Rotating credentials before exporting logs | You lose the audit trail showing what was accessed during the exposure window. | Export logs first, then rotate (unless the token is still live, revoke immediately). |
| Waiting to notify your team | Every hour of delay is an hour the team can’t protect downstream systems. | Notify within 15 minutes of confirming the leak. |
| Posting about it publicly before revoking | Announcing the leak signals attackers to move faster with whatever access they have. | Revoke first. Disclose after containment. |
Key insight: Force-pushing to remove a committed secret destroys your
git reflogaudit trail and does not remove the secret from GitHub’s event log, cached forks, or bot-scraped databases. Revocation must always precede history cleanup (GitHub Docs).
What’s the 7-day plan after the 60-minute runbook?
The 60-minute runbook stops the bleeding. The 7-day plan prevents infection. With 2 billion unique leaked credentials compiled from dark web combo lists in 2025 alone (Deepstrike, 2025), the question isn’t whether you’ll face another incident. It’s whether you’ll be prepared.
- Day 1-2: Monitor audit logs for any access during the exposure window that you missed. Set alerts for unusual activity on affected accounts.
- Day 3: Document the incident. What leaked, exposure window, what was rotated, what was accessed. Keep this doc for future reference.
- Day 4-5: Review secrets management. Are you using environment variables instead of hardcoded keys? Is
.envin.gitignore? Are CI secrets scoped to the minimum necessary? - Day 6-7: Mini-retro with the team (or with yourself). No blame. What process failed? What automation would have caught this? Would a PreToolUse hook have blocked the commit?
When should you call for professional help?
If the leaked credential had access to customer data, financial systems, or production databases with PII, stop following this guide and engage a professional incident response firm. The legal and regulatory requirements change the playbook entirely.
Thresholds for escalation:
- Customer data potentially accessed: legal obligation to disclose in many jurisdictions (GDPR: 72 hours, various US state laws)
- Production database credentials leaked: assume data exfiltration until proven otherwise
- Multiple tokens leaked simultaneously: possible broader system compromise, not just a single credential leak
Try it now:
- Run
npm token listand check if any tokens have no expiration or overly broad scope- Go to
github.com/settings/tokensand replace any classic PAT with a fine-grained token (90-day expiry, scoped to specific repos)- Enable Push Protection on your repos: Settings > Code security > Secret scanning > Push protection
- Bookmark this page. You’ll want it at 2am when the notification comes.
Want to prevent the next credential leak? Start with the 30-second .npmrc defense, then build up. Join AI Developer Weekly → for weekly security tips.
FAQ
How fast do bots scan GitHub for leaked keys?
Within 5 minutes. Automated scanners continuously monitor public commits on GitHub. Researchers have documented credential harvesting within minutes of exposure. By the time you notice the leak, the token may have already been copied. This is why Minute 0 is revocation, not investigation.
Should I delete the commit that contains the leaked key?
Not immediately. Revoke the token first. Export logs second. Then clean git history with git filter-repo or BFG Repo-Cleaner. Force-pushing before revoking destroys your audit trail without removing the exposure, because the commit data is already in GitHub’s event log and may have been cached by third-party services.
Does GitHub Secret Scanning catch all leaked tokens?
No. GitHub supports 39 token types with push protection enabled by default, including AWS, npm, Stripe, and Google Cloud. But custom API keys, database passwords, self-hosted service tokens, and internal secrets are not detected. Secret scanning is a safety net, not a guarantee. Pair it with .gitignore discipline and pre-commit hooks.
Is rotating the leaked token enough, or do I need to rotate everything?
Rotate everything the leaked token could access. If an npm token could read CI secrets, those secrets are compromised too. If a GitHub PAT had repo scope, every secret stored in those repos is exposed. If a Vercel env var contained database credentials, rotate at the database level. Follow the cascade described in the Minute 15-30 section.
What to Read Next
- The 30-Second npm Defense Every Vibe Coder Needs — Level 1 of the supply chain defense series. Four lines in
~/.npmrcprevent the most common attack vector. Start here for prevention after you’ve handled the incident. - OAuth Supply Chain Attacks: Your AI Tools Are the New Vector — Level 3. If the leaked credential could access OAuth tokens (e.g., via Vercel env vars), run this 5-minute audit to check your exposure.
- I Set Up 3 Layers of Defense in Claude Code. It Deleted My File Anyway. — The lesson that applies here too: test your actual threat model, not the one you imagine. Your incident response plan needs testing before the incident.