Resources/Guide

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.

10 min read·Feb 2026·KeyVault Edge Team

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:

Full git historyEvery commit, including deleted files and reverted changes
All branches and tagsFeature branches often have secrets that never made it to main
Docker image layersBuild-time ARGs and ENV instructions that baked in secrets
CI/CD pipeline configs.github/workflows, .gitlab-ci.yml - environment variables echoed in logs
Dependency lock filesRarely, but npm/yarn lockfiles can contain auth tokens
Build artifactsCompiled frontends that embedded env vars at build time

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 and run Gitleaks
# 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 json

The 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.

Add as pre-commit hook
# 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 install

Deep 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.

TruffleHog - verified credential scanning
# 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-verified

The --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 Docker image with TruffleHog
# 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 like env: OPENAI_KEY: sk-proj-... are not.
  • run: echo $OPENAI_API_KEY or 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:

1

Rotate the credential immediately

Do not wait for git history rewrite. The key may already be compromised. Rotate first.

2

Check for unauthorized usage

Review the provider's usage logs (OpenAI dashboard, AWS CloudTrail) for requests not made by your systems.

3

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.

4

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.

5

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