.env Leaked in a Screenshot — What to Rotate First

security secrets devops

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

  1. Production database credentials — issue a new password or rotate the role, update platform secrets, recycle connection pools, kill sessions still using the old password.
  2. 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.
  3. Payment / messaging providers — Stripe restricted keys, Twilio, SendGrid, Postmark. Check provider dashboards for unusual API usage while you rotate.
  4. OAuth client secrets and JWT signing keys — coordinate brief auth downtime; revoke sessions if signing keys change.
  5. CI/CD and package tokens — GitHub PATs, npm tokens, Docker registry creds often appear in the same terminal screenshots as app secrets.
  6. Observability and SaaS tokens — Sentry, Datadog, analytics write keys (lower urgency, still rotate).
  7. 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:

  1. Rotate (always).
  2. Remove from the working tree and ensure .gitignore covers .env*.
  3. 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

HabitReplacement
Pasting .env into Slack for “help”Redacted .env.example + share one key name
Full-screen IDE share in standupsWindow share or blur; hide terminal
Secrets in laptop files foreverPlatform env / vault for shared secrets
No pre-commit checksgitleaks 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.