status: active
timestamp: 2026-06-20
tags: [runbook, secrets, security, incident, envpact]
Rotate a leaked secret
Revoke, reissue, re-login, store via envpact, verify, audit leak
Rotate a leaked secret
Run this runbook the moment a secret is suspected leaked or has entered any transcript, screenshot, or untrusted log. “Suspected” is the trigger — don’t wait for confirmation.
Steps
-
Revoke at the provider’s dashboard. Open the dashboard URL for the affected provider — Firebase, Razorpay, Resend, GitHub, Cloudflare, etc. The full URL list lives in
auth-setup.md. Find the leaked credential and delete / disable it before doing anything else. Revocation must precede reissue — otherwise the leaked secret stays valid during the gap. -
Reissue a new credential. Same dashboard, same scope. Copy the new value to the clipboard once; don’t paste it into any chat.
-
Re-login locally if the credential is one a CLI uses (
gh auth login,firebase login,wrangler login, etc.). For pure API keys this step is skipped. -
Store via envpact. Per
../rules/security/no-hardcoded-secrets.md, every secret lives in envpact, never in.envfiles committed to git, never inline in source.envpact set <NAME> "<new-value>"Replace
<NAME>with the canonical env-var name the family uses for this credential. -
Verify the new credential works. Run the provider’s whoami / sanity check:
Provider Sanity check GitHub gh auth statusFirebase firebase projects:listCloudflare wrangler whoamiRazorpay curl their /v1/paymentswith limit=1Resend curl their /domainsendpoint -
Audit recent activity on the provider’s dashboard. Look at the “recent activity” / “audit log” / “API usage” section for the last 24-48 hours. Specifically scan for:
- calls from IPs / regions / user-agents you don’t recognise
- usage spikes that pre-date the rotation
- any successful charge, write, or email that wasn’t user-initiated
If anything looks anomalous, capture timestamps + IPs and escalate to the user before continuing further work.
-
Update
knowledge/log.mdwith a single dated entry:- 2026-06-20 — rotated <provider> <credential-name> after suspected leakDon’t include the old or new secret value, even partially.
Don’ts
- Don’t paste the old or new secret into chat to “verify it rotated”. The verification is the dashboard sanity check in step 5.
- Don’t grep the family for the old secret unless you’re certain the grep results don’t get logged anywhere. Use the provider’s audit log instead — it’s authoritative.
- Don’t postpone any step to “after I finish what I’m doing”. A partial rotation is worse than no rotation because it implies false safety.