🚨 STOP. Do these 3 things RIGHT NOW:

  1. 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>
  2. Assume everything the token could access is compromised.
  3. 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

Terminal window
# List your tokens to find the leaked one
npm token list
# Revoke it
npm token revoke <token-id>

GitHub PAT

Terminal window
# 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

Terminal window
# Deactivate first, then delete
aws 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:

Terminal window
vercel env rm <VAR_NAME> production
vercel env add <VAR_NAME> production

GCP

Terminal window
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 typeBlast radiusWorst-case access
npm publish tokenYour packagesAttacker publishes malicious versions
npm read-only tokenPackage metadataLow risk, but rotate anyway
GitHub classic PAT (repo)All repos, including privateSource code, secrets in code, CI configs
GitHub fine-grained PATScoped repos onlyLimited to selected repos
AWS IAM access keyDepends on IAM policyCould be everything in your AWS account
Vercel env varOne project’s secretsAPI keys, DB credentials, OAuth tokens

How to check what was accessed

GitHub: Check your security log for the exposure window:

Terminal 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:

Terminal window
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIA... \
--start-time 2026-04-28T00:00:00Z \
--end-time 2026-04-30T23:59:59Z

Exposure 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):

Terminal window
# GitHub Actions secrets - regenerate via web UI
# Settings > Secrets and variables > Actions > Update each secret
# Vercel env vars
vercel env ls production
# Regenerate any that the leaked token could have read

npm 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.

Terminal window
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:

Terminal window
# Generate new key
ssh-keygen -t ed25519 -C "your_email@example.com"
# Add to GitHub
gh 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

PlatformWhat to exportHowRetention
GitHubSecurity logSettings > Security log > Export90 days
AWSCloudTrail eventsaws cloudtrail lookup-events (see above)90 days default
VercelDeployment logsDashboard > Deployments > filter by date30 days
npmToken last-usednpmjs.com/settings/~/tokensLimited

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):

Terminal window
# Check if secret scanning is enabled
gh 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:

LevelDefensePost
1.npmrc hardeningThe 30-Second npm Defense
2PreToolUse hooksStop npm Attacks with Hooks
3OAuth audit + scope hygieneOAuth Supply Chain Defense
4Incident 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-patternWhy it’s worseDo this instead
Force-pushing to delete the commitToken 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 repoCommit was already scraped by bots. Now you’ve lost code AND logs.Revoke, export logs, then clean history.
Rotating credentials before exporting logsYou 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 teamEvery 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 revokingAnnouncing 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 reflog audit 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 .env in .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:

  1. Run npm token list and check if any tokens have no expiration or overly broad scope
  2. Go to github.com/settings/tokens and replace any classic PAT with a fine-grained token (90-day expiry, scoped to specific repos)
  3. Enable Push Protection on your repos: Settings > Code security > Secret scanning > Push protection
  4. 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.