How to Audit Your Codebase for Exposed API Keys (Free Tools)
Accidental credential commits are often discovered weeks or months after they happen - long after the exploitation window has closed. This guide walks through a systematic audit of your repositories, git history, Docker images, and CI pipelines using free, open-source tools.
What you're scanning and why it matters
A credential audit is not just scanning your current working tree. Secrets committed to git are permanent in history unless you rewrite it. Deleting a file with a secret in it does not remove the secret - the commit containing the original file is still accessible via git log and git show.
The scope of a proper audit includes:
Scanning git history with Gitleaks
Gitleaks (Apache 2.0, GitHub: gitleaks/gitleaks) is the most widely used open-source secret scanner. It ships with 150+ built-in rules covering OpenAI, AWS, Stripe, GitHub, Twilio, and most major providers.
# Install (macOS)
brew install gitleaks
# Install (Linux)
curl -sSL https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks_linux_x64.tar.gz | tar -xz
sudo mv gitleaks /usr/local/bin/
# Scan full git history (current directory)
gitleaks detect --source . --verbose
# Scan a specific repo
gitleaks detect --source /path/to/repo --verbose
# Output report to file
gitleaks detect --source . --report-path gitleaks-report.json --report-format jsonThe detect command scans all commits in the git history. For large repositories (10,000+ commits), this may take several minutes. The --log-opts flag accepts any valid git log options - use --log-opts="--since=2025-01-01" to scan only recent history.
# Using pre-commit framework
cat >> .pre-commit-config.yaml << 'EOF'
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.21.0
hooks:
- id: gitleaks
EOF
pre-commit installDeep scanning with TruffleHog
TruffleHog (AGPL-3.0, GitHub: trufflesecurity/trufflehog) goes further than Gitleaks by verifying detected credentials against their upstream APIs. It will tell you not just that a string looks like an OpenAI key, but whether that key is currently valid and active.
# Install
curl -sSL https://trufflesecurity.com/trufflehog-install | sh
# Scan a GitHub repository (public)
trufflehog github --repo https://github.com/yourusername/yourrepo
# Scan local git history with verification
trufflehog git file://. --only-verified
# Scan all your GitHub org repos
trufflehog github --org yourorgname --only-verifiedThe --only-verified flag is powerful for triage: it filters out false positives and surfaces only credentials that are currently exploitable. Run this on all repos before starting any migration project.
Scanning Docker images
Docker images built with ARG or ENV instructions that reference real API keys bake those keys into image layers permanently. Even if a later RUN instruction overwrites the environment variable, the original layer is still accessible.
# Scan a local image
trufflehog docker --image yourimage:latest
# Scan a Docker Hub image
trufflehog docker --image docker.io/yourorg/yourimage:tag
# Inspect image layers manually
docker save yourimage:latest | tar -xO | strings | grep -E 'sk-proj|AKIA|ghp_'Common Dockerfile mistake
# This bakes the real key into the image layer - WRONG ARG OPENAI_API_KEY ENV OPENAI_API_KEY=$OPENAI_API_KEY # Use runtime injection instead - inject via docker run or orchestrator secrets
Auditing CI/CD pipelines
CI pipelines are a common source of credential exposure because build logs are often made public, especially in open-source projects. Check for:
- ▸
env:blocks in workflow files that reference secrets via${{ secrets.X }}- these are fine. Direct values likeenv: OPENAI_KEY: sk-proj-...are not. - ▸
run: echo $OPENAI_API_KEYor any step that prints environment variables to the log. - ▸Test scripts that hardcode keys for “easier local testing” and got committed to the main branch.
- ▸Cached workflow artifacts that include environment variable dumps from crash reporters.
GitHub's built-in scanning
GitHub's Secret Scanning is enabled by default on all public repositories and can be enabled for private repos on Team and Enterprise plans. It scans every push in real time against patterns provided by partner providers including OpenAI, Stripe, AWS, GitHub, and 200+ others.
When a valid pattern is detected, GitHub alerts the repository owner and - for partner secrets - notifies the provider automatically. OpenAI can revoke a detected key within minutes of the alert.
Check your repo's scanning status at: Settings → Security → Secret scanning. Enable push protection to block commits containing known secret patterns before they land in the repository.
What to do when you find something
If Gitleaks or TruffleHog finds a secret in your history, the remediation steps are:
Rotate the credential immediately
Do not wait for git history rewrite. The key may already be compromised. Rotate first.
Check for unauthorized usage
Review the provider's usage logs (OpenAI dashboard, AWS CloudTrail) for requests not made by your systems.
Remove from git history
Use git-filter-repo (not git filter-branch) to rewrite history. Force-push to all remotes. Notify all contributors to re-clone.
Invalidate GitHub's cached view
Open a GitHub support ticket to clear cached views of the old commits. History rewrite does not automatically clear GitHub's search index.
Audit all forks
If the repo is public and was forked, the old commits may exist in fork history. You cannot control forks.
Never have to remediate again
KeyVault Edge sanitized tokens are designed to be committed. If a scan finds a token in your history, it is not a security incident - the token is worthless outside your authorised domains.
Get started free