.env Leaked in a Screenshot — What to Rotate First
Standup Zoom still on screen share. Slack #general gets a PNG of VS Code with DATABASE_URL and STRIPE_SECRET_KEY readable. Someone deletes the message and declares victory. That is not an incident response — that is hope. Image previews, mobile downloads, and email push notifications mean the pixels already left the channel.
Assume the secret left the building
Treat every readable secret in a chat image as public:
- Slack / Teams / Discord search and mobile offline caches
- Email and push notifications that inline image previews
- Future exports of channel history for compliance or offboarding
- Screenshots re-uploaded to Linear, Notion, or a customer ticket
Do not debate whether anyone “probably” saw it. Rotate. Deleting the Slack message reduces future accidental views; it does not revoke credentials.
Rotation order by blast radius
- Production database credentials — issue a new password or rotate the role, update platform secrets, recycle connection pools, kill sessions still using the old password.
- Cloud provider keys (AWS access keys, GCP service account keys, Cloudflare API tokens) — disable or delete the exposed key first, then create a replacement with least privilege.
- Payment / messaging providers — Stripe restricted keys, Twilio, SendGrid, Postmark. Check provider dashboards for unusual API usage while you rotate.
- OAuth client secrets and JWT signing keys — coordinate brief auth downtime; revoke sessions if signing keys change.
- CI/CD and package tokens — GitHub PATs, npm tokens, Docker registry creds often appear in the same terminal screenshots as app secrets.
- Observability and SaaS tokens — Sentry, Datadog, analytics write keys (lower urgency, still rotate).
- Staging and preview env clones — staging often copies production values “temporarily.” Rotate those too or you leave a back door.
Write a short incident note: secret type, where it appeared, who rotated, UTC timestamps. Future you will need it for the postmortem.
Parallel tracks while keys turn
- Secret scanning on git (
gitleaks, GitHub secret scanning, GitLab secret detection). A screenshot leak often correlates with an earlier commit of.env. - Provider audit logs — new API keys created, unusual regions, spike in 401s after rotation (clients still on old values).
- Purge mirrored uploads (CDN image hosts, public ticket attachments) when you control them.
- Access review — who can export Slack; was the channel public to the whole company?
- Customer impact — if DB or payment keys leaked, follow your breach playbook; do not improvise legal language in Slack.
Git history is not the first step
If the secret was ever committed:
- Rotate (always).
- Remove from the working tree and ensure
.gitignorecovers.env*. - Only then consider history rewrite (
git filter-repo) or accept that old SHAs remain poisoned and rely on rotation + scanning.
Rewriting history without rotation leaves the old secret valid in every clone that already fetched it. Rotation without cleaning history leaves copies for future scanners — still do both when practical, but rotation first.
Culture fixes that stick
| Habit | Replacement |
|---|---|
Pasting .env into Slack for “help” | Redacted .env.example + share one key name |
| Full-screen IDE share in standups | Window share or blur; hide terminal |
| Secrets in laptop files forever | Platform env / vault for shared secrets |
| No pre-commit checks | gitleaks or similar on commit and CI |
Keep .env.example with placeholder values only (DATABASE_URL=postgresql://user:pass@localhost:5432/app). Document required keys in README without real credentials. Prefer short-lived cloud credentials and OIDC into CI over long-lived access keys sitting in dotenv files.
Screenshot and demo muscle memory
Before any screen share: close .env / *.pem files, prefer window share over full desktop, and type fake values if you must show config shape.
After-action checklist
- High-blast secrets rotated and old ones disabled
- Deploy configs updated; apps healthy on new values
- Git and chat scanned for the same strings
- Provider logs reviewed for abuse window
- Postmortem scheduled; “delete and pray” called out as insufficient
Bottom line
Delete ≠ contained. Rotate database, cloud, and payment secrets first, then the rest. Audit git and chat in parallel. Treat every readable secret in a screenshot as already public — because for incident purposes, it is.