Skip to main content
When a developer accidentally pushes a password, private key, or API key to a public repo, every second matters. This guide provides a concise incident-runbook you can follow to revoke the credential, scrub Git history, and purge cached artifacts so the secret is removed as fully as possible. Imagine discovering that you or one of your developers has committed a production database password or private key to your repository.
A slide titled "One Accidental Commit" showing a developer icon on the left and a key/lock icon in the center with a callout listing "Private key" and "Production DB password." It illustrates accidentally committing sensitive secrets from a developer to a repository.
It’s a high-pressure situation. As a GitHub administrator (or incident responder), you need a repeatable, ordered runbook — what to do first, what to do next, and how to bring the repository back to a safe state.
The slide titled "From Panic to a Plan" contrasts a "Pure Panic" scenario where a secret is exposed to the web with a resolved state labeled "GitHub Administrator." An arrow links the left box showing a leaked secret icon to the right box showing a user/GitHub administrator icon.
First principle — neutralize the credential immediately. Do not try to rewrite history before revoking the exposed credential. Assume compromise and go straight to the provider (AWS, Azure, Stripe, etc.) to rotate or delete the key. This prevents further damage while you prepare a safe repository cleanup.
Revoke credentials at the source (rotate API keys, delete the secret, enforce new credentials) before attempting repository cleanup.
A slide titled "Revoke the Credential First" showing a central green checkmark between a client icon and three source-provider cards (AWS, Azure, Stripe), each labeled "Revoked." Arrows indicate the revocation flow from the providers back to the client.
Why revocation first? Because simply deleting a file or committing a fix does not remove the secret from Git history. Git preserves past commits, so the secret may still be accessible from earlier revisions. Example of an accidentally committed secrets file:
Even if you remove this file in a later commit, the value is still present in earlier commits. To remove it entirely you must rewrite the repository history. Tools that can perform history rewrites Both tools scan every commit, branch, and tag and can remove files or replace secrets across the entire history.
A presentation slide titled "Rewrite the Story" showing two tools—git filter-repo and BFG Repo-Cleaner—and a simplified Git branch diagram (main, feature/checkout, release/v2.0). Several commits are marked with orange key icons and a vertical blue line indicating the history-rewrite point.
Practical examples
  • git-filter-repo: remove a file from all commits
  • git-filter-repo: replace specific secret strings using a mapping file
Create replacements.txt:
Run the replacement:
  • BFG Repo-Cleaner: delete a file from history
Important operational notes:
  • Always operate on a mirrored clone (--mirror) so you capture all refs, branches, and tags.
  • Test the workflow on a disposable copy or run a dry run first. Mistakes in history rewriting are destructive.
  • After rewriting history locally, you must push the rewrites to GitHub with force pushes.
History-rewriting and force-pushing are destructive: notify your team, coordinate a maintenance window, and ensure you have backups before you proceed.
An illustration titled "Force GitHub to Accept It" comparing two panels: a green "Local — Rewritten" view with clean, rewritten branch timelines (main, feature/checkout, release/v2.0) and an orange "GitHub — Old History" view showing the original, differing commit histories with conflict markers.
Force-push the rewritten history to GitHub
Notify collaborators: after a forced history rewrite, local clones will diverge. Provide clear instructions for recovery. Two safe options:
  • Re-clone (simplest and safest):
  • If a collaborator must preserve local work: create patches or branches, then reset to the new remote
One commonly missed step: GitHub may retain cached references to the old commits in closed pull requests, activity logs, or internal caches. To try to eliminate these remnants, request GitHub to run repository garbage collection.
A clean slide titled "Ask GitHub Support" showing buttons labeled "GitHub support" and "Run garbage collection." Below is a rounded purple header that reads "Lingering cached fragments" above an empty white content area.
When you contact GitHub Support, include:
  • Repository name and URL
  • Timestamp and clear description of the sensitive-data exposure
  • Confirmation that you have force-pushed rewritten history
  • A request that GitHub run garbage collection and purge cached fragments
Prevent future leaks The most effective control is to stop secrets from entering your repo. Enable secret scanning and push protection so that pushes containing recognized secret patterns are blocked before they land on the server.
A slide titled "Prevent It Entirely" showing a flow where a code push containing a password is intercepted by secret scanning and push protection, triggering "Upload blocked — password detected." The result shown is the repository stays clean.
Resources Quick reference — runbook summary Following this ordered runbook — revoke first, rewrite history carefully on a mirrored clone, force-push, and follow up with GitHub Support and team coordination — minimizes exposure and restores a clean repository state.

Watch Video