Key takeaways
- Treat any secret that reached a shared repository as exposed. Revoke and rotate it first. Cleaning history comes second.
- Rewriting history does not recall copies. Clones, forks, pull request refs, caches and CI logs may still hold the value.
- Scan the full history, not just the current files. Gitleaks and TruffleHog do this, and GitHub secret scanning covers repositories on that platform.
- Push protection and pre-commit scanning stop most new leaks before they land.
Start with the answer: if a password, API key, token or private key was ever committed to a repository others can reach, assume someone has it. Revoke it at the provider, issue a new one, and check the provider's logs for use you did not make. Only then clean the repository. The order matters because cleanup takes time and does nothing about copies that already exist.
Why deleting the file does not help
Git keeps every commit. A later commit that removes the secret leaves the old version one command away. The value also lives in every clone, in forks, in the references that platforms keep for pull requests, in CI build logs and in local caches. Automated scrapers watch public platforms for new keys and test them within minutes, so for a public repository, speed is the whole game. For a private repository the exposure is smaller but real: contractors, former staff, compromised laptops and later acquisitions all inherit the history.
Step 1: find them, in all of history
Scan every commit on every branch, not only the checked-out tree. Two widely used open-source tools do this. Gitleaks matches patterns and entropy across history and can run in a pipeline or as a pre-commit hook. TruffleHog also scans history and can go further by trying to verify whether a detected credential is still live against the provider, which helps you rank what to do first. Both produce false positives, so a person confirms each hit. GitHub secret scanning runs on repositories hosted there and alerts on known token formats from partner providers.
Do not forget the places a repository scan misses: issue and pull request text, wiki pages, container image layers, build logs, chat exports and configuration backups.
Step 2: revoke and rotate
- Revoke the exposed credential at the issuer. For a cloud access key, deactivate then delete it. For a database password, change it and the application setting together.
- Issue a replacement and store it in a secrets manager, not in the repository. Give it the least access the job needs.
- Review the provider's access logs from the date of the commit forward. Look for use from unfamiliar addresses, new resources, new users or data exports.
- If the log shows misuse, move to incident response and scope the data involved. Notification duties may apply.
Rotation is not optional even when the repository is private and the log looks clean. You cannot prove nobody copied it.
Step 3: clean the history, knowing its limits
Removing the secret from history reduces future exposure and keeps scanners quiet. GitHub's guidance describes using a history-rewriting tool such as git filter-repo to remove a file or string from all commits, then force-pushing and asking collaborators to re-clone. The same guidance is plain about limits: the value may remain in cached views, forks and pull request references until the platform clears them, and you may need to contact support. A rewrite also changes every commit hash after the change, which breaks signed commits, open branches and tags for everyone. Do it with a plan, and in teams with a clean-up date everyone knows. Never use a rewrite as a substitute for rotation.
Step 4: stop the next one
- Turn on push protection, which blocks a push that contains a recognized secret and asks the developer to resolve it before it lands.
- Run Gitleaks or an equivalent as a pre-commit hook and again in the build pipeline, so a local skip does not slip through.
- Keep configuration in environment variables or a secrets manager. Commit example files with placeholder values only.
- Use short-lived credentials where you can, such as cloud role assumption and workload identity, so a leak expires on its own.
- Add generated and local files to the ignore list from the first commit.
Make it routine
A one-time scan is a snapshot. Run history scans on a schedule, track findings to closure, and write down who owns rotation for each provider. A short runbook that lists where each credential type is revoked saves the most time during a real leak. Our article on what a code and endpoint review finds on day one shows why leaked credentials top the usual list.
Our cybersecurity team scans repositories and pipelines under written authorization, confirms each finding by hand, and helps set up the controls that prevent repeats. Start with our Cybersecurity service.
Sources
- About secret scanning (GitHub Docs)
- About push protection (GitHub Docs)
- Removing sensitive data from a repository (GitHub Docs)
- Gitleaks (open-source project)
- TruffleHog (open-source project)
- OWASP Top 10:2021, A07 Identification and Authentication Failures
This article is general information, not legal advice. Your obligations and the right steps depend on your systems, contracts and the laws that apply to you. Last reviewed .
Keep reading
Next · SoftwareMulti-Tenant SaaS Isolation: Row-Level Security and Per-Tenant KeysMost multi-tenant data leaks are a missing filter, not a broken cipher. Row-level security makes the database enforce the tenant boundary, and per-tenant keys limit the damage if it fails. Here is how the two layers fit together.7 min read- What a Code and Endpoint Security Review Finds in the First 24 Hours7 min
- Before Anyone Scans Your Website: Verification and Written Authorization7 min
Need help with this?
We find out whether everything you run is safe from attackers, then we fix it.
Cybersecurity