Skip to content

Secrets in Git and CI/CD: Why Deleted Keys Still Work

Secrets in Git and CI/CD: an API key recovered from the commit before its deletion and a deploy token echoed in a build log, fixed by revoking the key before scrubbing history

A leaked secret in Git or CI/CD is any credential, such as an API key, deploy token or private key, that ends up in a repository’s history, a tracked file or a build log. Deleting it from the latest commit does not revoke it. Anyone with a clone or log access can still read and use it until the credential itself is rotated.

This post covers the four places secrets leak in a delivery pipeline, the order to fix them in, and the guardrails that stop the next one.

Two patterns cause most Git leaks. The first is a hardcoded key that someone later “removes” in a cleanup commit. The second is a whole secrets file, like .env, a private key or a service-account JSON, tracked from the first commit because the repository never had a .gitignore.

Both look fine in the current tree. That is why they survive for years.

Does deleting a secret from Git remove it?

Section titled “Does deleting a secret from Git remove it?”

No. Git keeps every version of every file, so the value still sits in the commit before the cleanup. One git log -p or git show <commit>^:config.js brings it back, and every fork and clone carries its own copy.

The secrets in Git history exercise makes this concrete. You find the commit that claims to remove a production API key, read the key from the commit before it, and replay it against the live admin API. The committed secret files exercise does the same for a tracked .env that leads straight to a staging environment.

Build logs are more public than workflow authors assume. A debug step that runs echo $DEPLOY_TOKEN prints the secret in plain text, and on a public repository anyone can read that log.

The same workflows often carry a second flaw: untrusted input, such as a pull request title, interpolated straight into a run: step. That input executes as shell on the runner, with the pipeline’s secrets in reach. Unpinned third-party actions add a third path, because a moved tag can swap in code you never reviewed.

In the CI/CD secret exposure exercise you lift a deploy token from public Actions logs and ship your own image with it. Then you fix the workflow and rotate the token.

What should you do first when a secret leaks?

Section titled “What should you do first when a secret leaks?”

Rotate first. Revoke the leaked credential and issue a scoped replacement before you touch history, logs or code.

Scrubbing history with git filter-repo or masking future logs feels like the fix, but it does nothing to a key an attacker already copied. Clean up after the credential is dead.

How do you prevent secrets leaking into Git and pipelines?

Section titled “How do you prevent secrets leaking into Git and pipelines?”
  • Block secret files at commit time. Add a .gitignore for .env, keys and credential JSON, and a pre-commit hook that rejects secret filenames and patterns.
  • Scan in CI. Run a secret scanner on every push so a leak becomes a failed build instead of a public commit.
  • Never echo secrets. Remove debug prints, and rely on the platform’s masking only as a backstop.
  • Treat pipeline input as untrusted. Pass PR titles, branch names and issue text through environment variables, never inline into shell.
  • Pin actions by commit SHA, not by tag.
  • Prefer short-lived credentials, such as OIDC federation to your cloud, so a leaked token expires on its own.

Container images have the same problem one layer down. A token passed into a RUN step stays in that layer even if a later step deletes the file, which our container security best practices post covers in detail.

Train developers on the leak, not just the policy

Section titled “Train developers on the leak, not just the policy”

Most engineers know they should not commit secrets. What changes behavior is finding a “deleted” key in history and watching it still authenticate.

The Git Security catalogue is built around that exploit-then-fix loop, and the Cloud Security catalogue applies it to images and cloud infrastructure. Want to roll it out to your engineering team? Talk to us.