How secrets leak: git, logs, images, screenshots

Reading · 6 min · Module 6, lesson 2 of 536 min left in this module

Module 6 · SecretsLesson 2 of 5

Goal: Name the four common ways a secret leaks from an app, and the habit that closes each one.

3:49 · captions and chapters · narrated with an AI-generated voice
Transcript

Narration uses an AI-generated voice.

[00:00] Where we're going

By the end of this video, you'll know the four common ways a secret leaks, and the habit that closes each one. Most secrets don't leak through an attack. They leak through ordinary work. A commit. A log line. A container image. A screenshot.

[00:18] Git

Start with git. A key written into a file gets committed, pushed and cloned. Deleting it in the next commit doesn't help. The old commit still holds it, and every clone has a copy. Public repositories are scanned for keys by automated tools, often within minutes of a push.

[00:38] Watch it happen

Let's watch it happen. Here's a sample repository, with a fake key. Clone it, and list the commits. The newest reads the key from the environment. Search the latest files for the key. Nothing. By this check, the repository looks clean.

Now search the history instead. The newest commit removes the key. That's the minus line. And the one before it added the key. There it is, in full. Or ask for the old version of the file. Same key. Anyone who clones the repository can do this.

So here's the habit. Read secrets from the environment. Put dot env in your git ignore file before your first commit. And run a secret scanner before you push.

[01:27] Logs

Next, logs. They're copied to more places, and kept longer, than anyone expects. Watch for code that prints its whole configuration at start-up. Errors that include a full connection string. And request logging that records the authorization header. The habit: log the names of settings, never their values. If you must show part of one, show the last four characters.

[01:56] Images

Third, images. Anyone who can download an image can read everything in it. A build can copy your dot env into the finished app, along with the code. And a key that gets in stays in. The habit: keep dot env out of the build, and give secrets to the app when it runs.

[02:17] Screenshots and pastes

Fourth, screenshots and pastes. A terminal screenshot in a bug report. A screen share during a demo. A config pasted into a chat, or an AI assistant. Each one copies the secret somewhere you don't control. The habit: before you share, look for values, not just names. Paste the example file, not the real one. And stop sharing before you open a page with keys on it.

[02:45] When one gets out

If a key gets out anyway, one rule covers all four. Rotate it first. Create a new key, and give it to your app. Then revoke the old one, so it stops working. Only then, remove the copies. Removing copies without rotating leaves the key working for anyone who already saw it.

[03:07] Recap

To recap. Keep keys out of files, because git keeps every commit. Log names, not values. Give secrets at run time, not build time. Look for values before you share. And if one leaks, rotate first.

Here's a question to check yourself. You committed a key yesterday, and removed it today. The repository is private. Are you done? No. Anyone with access can still read it in history. Rotate the key, then clean the history. Next, you'll find a key in history, and remove it properly. I'll see you there.

Key idea

Most secrets don't leak through an attack. They leak through ordinary work: a commit, a log line, a container image, a screenshot. Each path has one habit that closes it, and all four share one rule: once a secret has leaked, rotate it.

1. Git

A key written into a file gets committed, pushed and cloned. Deleting it in the next commit doesn't help, because the old commit still holds it and every clone has a copy. Public repositories are scanned for keys by automated tools, often within minutes of a push.

The habit: read secrets from the environment (lesson 2.4.1), put .env in .gitignore before your first commit (lesson 2.5.5), and run a secret scanner before you push. The next lesson finds a key in history and removes it.

2. Logs

Logs are copied to more places, and kept longer, than anyone expects. The usual culprits are code that prints its whole configuration at start-up, errors that include a full connection string, and request logging that records the Authorization header.

The habit: log the names of the settings you loaded, never their values. If you must show part of one, show the last four characters.

3. Images

A build packages your app into a container image, and anyone who can download the image can read everything in it. A build can copy your .env into the finished app along with the code, and a key that gets in stays in.

The habit: keep .env out of the build, and give secrets to the app when it runs, not when it's built (lesson 2.4.3). Path 3 shows how, in lesson 3.4.4.

4. Screenshots and pastes

A terminal screenshot in a bug report, a screen share during a demo, a config pasted into a chat or an AI assistant to ask for help. Each copies the secret to a place you don't control.

The habit: before you share, look for values, not just names. Paste .env.example rather than .env, and stop screen sharing before you open a settings page with keys on it.

When one gets out anyway

Cleaning up comes second. First rotate: create a new key, give it to your app, then revoke the old one at the provider so it stops working. Only then remove the copies. Removing copies without rotating leaves the key working for anyone who already saw it.

Tools that catch leaks early
  • Secret scanners such as gitleaks or trufflehog check files and history for strings that look like keys. Run one as a pre-commit hook (a script Git runs before each commit, which can stop it) and in CI (continuous integration: jobs that run on every push, such as the GitHub Actions in Module 7).
  • GitHub secret scanning and push protection flag known key formats in repositories.
  • Image scanners check a built image for keys and other problems.

None of these catch everything, so the habits above still matter.

Check yourself

You committed a key yesterday and removed it in today's commit. The repository is private. Are you done?
You share your screen to get help with an error, and your terminal shows the output of cat .env. The call wasn't recorded. What now?

In the docs