← All articles

How to Find Exposed API Keys in Your Git Repository (Before an Attacker Does)

June 9, 2026

Why Git History Is a Credential Graveyard

Developers move fast. A Stripe secret key gets pasted into .env for a quick test, the file accidentally lands in a commit, someone notices and deletes it—but the damage is already done. Git history is append-only by design. That deleted file still lives in every clone of the repo, readable with a single git log or git show command.

The same pattern plays out with CI/CD configs, Docker Compose files, Kubernetes manifests, and Terraform state files. Credentials find their way in during late-night debugging sessions and stay there indefinitely. Attackers know this, and automated scanners continuously probe public repositories looking for exactly these patterns.

What Counts as an Exposed Credential?

Before you scan, it helps to know what you're looking for. Common categories include:

  • API keys and tokens — AWS access keys, GitHub personal access tokens, Stripe/Twilio/SendGrid API keys, Slack bot tokens.
  • Service account credentials — GCP JSON key files, Azure service principal secrets embedded in config.
  • Database connection strings — anything containing password=, ://user:pass@, or similar patterns.
  • Private keys and certificates — PEM-encoded RSA/EC keys, JWT signing secrets.
  • OAuth client secrets — often mistaken for "safe" because they require a redirect URI, but still dangerous.
  • Hardcoded .env values — even when .env is in .gitignore, a single slip can expose it.

Step 1 — Audit Your Current Working Tree

Start with what's in your current codebase. A fast manual pass uses grep with patterns common to real credentials:

# Look for AWS-style access keys
grep -rE "AKIA[0-9A-Z]{16}" . --include="*.env" --include="*.json" --include="*.yml"

# Catch generic "secret" or "api_key" assignments
grep -rniE "(api_key|api_secret|access_token|client_secret)\s*=\s*['\"][^'\"]{8,}" .

This is a reasonable first pass, but regex alone has a high false-positive rate and misses obfuscated or base64-encoded values. Treat it as a triage step, not a final answer.

Step 2 — Scan Your Full Git History

This is where most teams have blind spots. A secret committed two years ago and "deleted" in a follow-up commit is still fully accessible. Tools like git-secrets, truffleHog, and gitleaks can walk the entire commit graph:

# Using gitleaks on a local repo
gitleaks detect --source . --verbose

# Scanning history specifically
gitleaks detect --source . --log-opts="--all"

Pay attention to:

  • Merge commits and feature branches that may never have been squashed.
  • Stash objects (git stash list) which are not always scanned by default.
  • Submodules — they carry their own independent history.
  • Tags pointing at older commits that predate your security practices.

Step 3 — Check .env Files and Config Templates

Even if your .env is gitignored, check that no committed template file (.env.example, .env.sample) contains real values rather than placeholders. A surprisingly common mistake is copying a working .env to .env.example and committing it directly.

Also audit your CI/CD pipeline definitions (GitHub Actions .yml, GitLab CI, CircleCI config) for inline secrets. Secrets should always be injected via your CI platform's secret store, never hardcoded in the pipeline file itself.

Step 4 — Remediate Found Secrets Immediately

Finding a leaked secret triggers a specific remediation sequence. The order matters:

  1. Revoke and rotate first. Before you do anything to the repo, invalidate the exposed credential. An attacker monitoring public repos can act in minutes; rewriting history takes longer.
  2. Rewrite history (if the repo is private and you control all forks). Use git filter-repo (preferred over the older BFG Repo Cleaner) to purge the file or value from all commits, then force-push and have all collaborators re-clone.
  3. If the repo is public, assume the secret is burned. History rewriting won't help—GitHub and other forges cache content, and bots may have already captured it. Rotation is your only real fix.
  4. Audit access logs. Check whether the exposed key was actually used. AWS CloudTrail, GCP Audit Logs, and most SaaS platforms provide usage history. Look for unusual source IPs, regions, or API calls.
  5. Document the incident. Even a brief internal write-up captures what happened and prevents recurrence. This record is also useful evidence for SOC 2 auditors.

Step 5 — Put Prevention in Place

Remediation without prevention is a treadmill. Add these controls so the same mistake can't recur silently:

  • Pre-commit hooks — Install gitleaks or detect-secrets as a pre-commit hook so secrets are blocked before they ever reach the remote.
  • Push protection — GitHub Advanced Security and similar platforms can block pushes containing known secret patterns at the server side, catching anything a local hook missed.
  • A secrets manager — AWS Secrets Manager, HashiCorp Vault, and Doppler are all designed so your application fetches credentials at runtime rather than storing them in files.
  • Least-privilege IAM — Even if a key leaks, scoping it to the minimum required permissions limits the blast radius.
  • Regular rotation schedules — Treat API keys like passwords. Many platforms (AWS, GCP) support automatic rotation. Build it into your runbooks.

The SOC 2 / HIPAA Angle

If your organization is pursuing or maintaining SOC 2 Type II or HIPAA compliance, exposed credentials aren't just a security problem—they're an audit finding. SOC 2's CC6.1 (logical access controls) and CC6.7 (transmission protection) directly address how credentials must be managed. HIPAA's Security Rule requires covered entities to implement technical safeguards protecting ePHI, which extends to the API keys that access systems storing that data.

Auditors increasingly ask for evidence of continuous secret scanning, not just a one-time review. Automated tooling that produces scan logs and maps findings to controls provides the paper trail your auditors need.

Get a Baseline in About 60 Seconds

Manual grep and local tooling are valuable, but they require setup, maintenance, and security expertise to tune correctly. If you want a fast, mapped baseline across your repos and .env files—including findings aligned to SOC 2 and HIPAA controls—run a free GhostCred scan and see what's actually exposed before someone else does.

Quick Reference Checklist

  • ☐ Grep working tree for common credential patterns.
  • ☐ Scan full Git history, including all branches and tags.
  • ☐ Audit .env.example and CI pipeline files for inline secrets.
  • ☐ Revoke any found credentials before rewriting history.
  • ☐ Check provider access logs for signs of exploitation.
  • ☐ Install pre-commit hooks and enable push protection.
  • ☐ Migrate to a secrets manager; eliminate file-based credentials.
  • ☐ Schedule periodic rotation for all long-lived keys.

See what's exposed in your own code.

Run a free scan