An API key pasted into a config file "just for testing" is one of the most common security mistakes in software, and one of the most damaging. Hardcoded credentials are catalogued as CWE-798, and the reason they persist is simple: they work, they are convenient and they are easy to forget once the code is committed.

Why are committed secrets such a problem?

Source code travels. It is cloned to laptops, copied into forks, uploaded to build systems, shared with contractors and sometimes made public by accident. A secret in the code travels with it. Worse, version control remembers: deleting a key in a later commit does not remove it from history, so anyone with access to the repository can still read it.

What should a reviewer look for?

  • Strings assigned to variables named password, secret, token, api_key or similar.
  • Connection strings with embedded credentials.
  • Private keys, certificates and service account files in the repository.
  • Credentials in test fixtures, sample configs, scripts, Dockerfiles and CI workflow files.
  • "Temporary" backdoor accounts or default passwords that ship to production.
  • Secrets passed on command lines or written to logs.

Do not stop at the current diff. Check the commit history of files the pull request touches, because the mistake may already be in the past.

Which tools help?

Secret scanners such as gitleaks and TruffleHog look for known key formats and high-entropy strings, and some repository hosts offer built-in secret scanning. Run them in three places:

  • Locally, as a pre-commit hook, so a secret is caught before it is ever committed.
  • In CI, on every pull request, as a safety net.
  • Across full history, periodically, to find what slipped through before the tools were in place.

What do you do when you find one?

  1. Revoke and rotate the secret first. Assume it is compromised the moment it was committed. This matters more than anything else on the list.
  2. Check the provider's access logs for use you do not recognize.
  3. Remove it from the code and replace it with a reference to a secret store or environment variable.
  4. Only then consider rewriting history, understanding that clones and forks may keep copies.

Where should secrets live instead?

Use a dedicated secrets manager or your platform's secret store, inject values at deploy or run time, and give each environment its own credentials with the least privilege needed. Prefer short-lived credentials where the platform supports them. If you want help finding exposed credentials across your repositories, it is a standard part of a secure code review.

Related reading: Code Review for Authentication and Authorization Flaws and Reviewing Cryptography Code: Common Mistakes to Catch.

Key takeaways

  • Deleting a secret from the code does not remove it from version control history.
  • Scan pre-commit, in CI and across history, and review the history of files you touch.
  • Rotate first, clean up second.
  • Keep secrets in a secrets manager and inject them at run time with least privilege.