It happens more often than teams like to admit: a developer commits a file, pushes it to GitHub, and only later realizes it contains something like an API key. Sometimes it's obvious. Sometimes it's buried in a config file. Either way, once it's in the repo—even briefly—you should assume it's compromised.
If you've ever seen a string that looks like sk-proj-... sitting in your commit history, you're not just dealing with messy code—you’re dealing with a security incident.
First, don’t try to “hide” it — assume it's exposed
A common mistake is thinking: “I'll just delete the file and push again.” That doesn’t solve the problem. Git history is immutable unless rewritten, and bots actively scan public repositories for leaked credentials within seconds.
So the priority isn’t hiding it. It’s damage control.
Immediate response checklist
- Revoke the API key from the provider dashboard immediately
- Generate a new key and update your applications
- Audit usage logs for suspicious activity
- Remove the key from your codebase
Revocation should always come first. Even if you plan to clean up Git history, assume the key has already been scraped.
Removing secrets from Git history (the right way)
Deleting a file doesn’t remove it from previous commits. To fully erase sensitive data, you’ll need to rewrite history.
One commonly used tool is git filter-repo:
1git filter-repo --path path/to/file --invert-pathsOr, if the secret is embedded inside a file:
1git filter-repo --replace-text <(echo "sk-proj-***==>REMOVED")After rewriting history, force push:
1git push origin --force --allBe careful: this rewrites commit history for everyone. Coordinate with your team before doing this.
GitHub’s built-in secret scanning
Here’s where things get interesting. GitHub already tries to help you catch these mistakes.
With GitHub Secret Scanning enabled, the platform can detect known token formats and alert you immediately. In some cases, it even notifies the provider to auto-revoke the key.
You can enable it under:
- Repository Settings → Security → Secret Scanning
For organizations, it’s worth enforcing this across all repos.
Preventing this from happening again
Once you've cleaned things up, the real question is how to avoid a repeat.
1. Use environment variables, not hardcoded secrets
Instead of this:
1const apiKey = "sk-proj-123...";Do this:
1const apiKey = process.env.API_KEY;2. Store secrets in GitHub Actions securely
GitHub provides encrypted secrets for workflows:
- Settings → Secrets and variables → Actions
Then reference them safely:
1env:
2 API_KEY: ${{ secrets.API_KEY }}3. Add a .gitignore (and actually use it)
Make sure files like these are excluded:
- .env
- config.local.json
- secrets.yml
4. Pre-commit hooks for safety
Tools like gitleaks or husky can scan commits before they’re pushed.
Example with gitleaks:
1gitleaks detect --source .A subtle but important point
Even if your repository is private, you should treat exposed API keys the same way. Insider threats, misconfigured access, or future exposure can all turn a “safe” leak into a real problem.
When should you rotate keys regularly?
Not just after leaks. Good DevOps hygiene includes periodic key rotation:
- Every 30–90 days for sensitive services
- Immediately after team member offboarding
- After any unusual activity
Final thought
Leaking an API key isn’t the end of the world—but ignoring it is. Fast response, proper cleanup, and better guardrails will turn a scary moment into a one-time lesson instead of a recurring incident.
If a secret ever touches your Git history, treat it as public—because it probably already is.