> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Scrub Compromised Secrets git filter repo

> Guide demonstrating how to safely remove leaked secrets from Git history using git-filter-repo, including revocation, replace-file creation, fresh or mirror clones, and force-pushing rewritten history.

If a developer accidentally commits a secret to your GitHub repository, treat that secret as compromised and immediately rotate or revoke it. After revocation, you can rewrite repository history to remove the leaked value using `git-filter-repo` (or replace the exact string across all commits).

![A presentation slide titled "Scrub Compromised Secrets - git-filter-repo" with a large blue teardrop-shaped graphic on the right containing the word "Demo." The slide includes a small "© Copyright KodeKloud" notice.](https://mintcdn.com/kodekloud-c4ac6d9a/TlnHw4JjIHBx3Cta/images/GitHub-Administration-Certification/Monitoring-and-Optimization/Demo-Scrub-Compromised-Secrets-git-filter-repo/scrub-compromised-secrets-git-filter-demo.jpg?fit=max\&auto=format\&n=TlnHw4JjIHBx3Cta\&q=85\&s=e9f18a3953063d10c42fd71095841ba4)

This guide demonstrates a safe workflow using a small test repository and a mock secret. It covers cloning best practices, creating a replace-file, running `git-filter-repo`, and force-pushing rewritten history.

## Lesson overview

* Create a small test repo on GitHub.
* Simulate a leaked secret by committing a test file.
* Revoke the secret in any external service.
* Use `git-filter-repo --replace-text` to remove or replace the value across history.
* Force-push the new history and coordinate with collaborators.

## Create a test repository on GitHub

For this demo we used a repo named `test-secret` (public) with a single `README.md`.

![A dark-mode screenshot of GitHub's "Create a new repository" page with the owner dropdown open and "test-secret" entered as the repository name. Repository configuration options like visibility, README, .gitignore, and license are visible below.](https://mintcdn.com/kodekloud-c4ac6d9a/TlnHw4JjIHBx3Cta/images/GitHub-Administration-Certification/Monitoring-and-Optimization/Demo-Scrub-Compromised-Secrets-git-filter-repo/github-create-repo-dark-test-secret.jpg?fit=max\&auto=format\&n=TlnHw4JjIHBx3Cta\&q=85\&s=9f8ef4b7a4f3f9846c5da524552adcde)

After creating the repo you will see only the initial commit on the `main` branch and the `README.md`.

![A dark-mode GitHub repository page for a public repo named "test-secret," showing the main branch, an initial commit and a README.md file. The README title "test-secret" is visible and the right sidebar lists repo details (no stars, forks, or releases).](https://mintcdn.com/kodekloud-c4ac6d9a/TlnHw4JjIHBx3Cta/images/GitHub-Administration-Certification/Monitoring-and-Optimization/Demo-Scrub-Compromised-Secrets-git-filter-repo/github-dark-test-secret-initial-readme.jpg?fit=max\&auto=format\&n=TlnHw4JjIHBx3Cta\&q=85\&s=76a8a3833a4c01a79449b7a478686bde)

## Simulate a leaked secret (local)

1. Clone the repo locally.
2. Create a `secret.txt` file containing a mock secret:

```text theme={null}
password=1234567
```

3. Commit and push the file:

```bash theme={null}
git add secret.txt
git commit -m "added secret - 1"
git push origin main
```

Example push output (condensed):

```bash theme={null}
To https://github.com/sid-dev2-kk/test-secret
   d8f5de1..ef9bc14  main -> main
```

At this point the secret exists in the repository history (older commits). Before attempting to rewrite history, revoke or rotate the compromised credential with the issuing service (API provider, cloud console, etc.).

Always rotate or revoke any exposed credentials immediately. Rewriting Git history removes the secret from the repo, but external systems, CI logs, or third parties may have already copied or used the secret.

## Removing the file from the tip (does not remove it from history)

If you simply delete the file and push, the secret is removed only from the latest tree — earlier commits still contain the secret:

```bash theme={null}
# delete locally and commit removal
rm secret.txt
git add .
git commit -m "removed secret file - 2"
git push origin main
```

To remove the sensitive value entirely from the repository history you must rewrite the repository history (see next section).

## Use git-filter-repo to replace the secret across history

Prerequisite: install git-filter-repo (not included with core Git). Official repo: [https://github.com/newren/git-filter-repo](https://github.com/newren/git-filter-repo)

Install via pip on many systems:

```bash theme={null}
pip3 install git-filter-repo
```

Important workflow notes:

* Operate on a fresh clone in a separate directory to avoid corrupting active clones.
* Rewriting history requires a force-push and coordination with all collaborators because commit IDs will change.
* For rewriting all refs and tags, use a mirror clone.

Steps used in this demonstration:

1. Clone the repo into a fresh folder (example `cleanup-repo`):

```bash theme={null}
git clone https://github.com/sid-dev2-kk/test-secret cleanup-repo
cd cleanup-repo
```

If you prefer to rewrite every ref and tag (including refs not fetched in a normal clone), use a mirror clone:

```bash theme={null}
git clone --mirror https://github.com/sid-dev2-kk/test-secret cleanup-repo.git
cd cleanup-repo.git
```

2. Create a replace-file listing the target text and replacement. Format is `OLD==>NEW`. For this demo we replace `1234567` with `***REMOVED***`. Save it as `/tmp/mock-expression.txt`:

```text theme={null}
# /tmp/mock-expression.txt
1234567==>***REMOVED***
```

Notes:

* Lines beginning with `#` are comments.
* Matches are literal by default; include exact surrounding characters if needed.

3. Run git-filter-repo with the replace-text option:

```bash theme={null}
git filter-repo --replace-text /tmp/mock-expression.txt
```

Typical output (condensed):

```bash theme={null}
Parsed 3 commits
New history written in 0.01 seconds; now repacking/cleaning...
Repacking your repo and cleaning out old unneeded objects
HEAD is now at 0fcc945 removed secret file - 2
Completely finished after 0.04 seconds.
```

4. Re-add remote (if needed) and force-push the rewritten history back to GitHub:

```bash theme={null}
git remote add origin https://github.com/sid-dev2-kk/test-secret
git push origin --force --all
# Also push tags if you have them
git push origin --force --tags
```

If you used a mirror clone, push the entire mirror back with force:

```bash theme={null}
git push --mirror --force
```

Example force-push output:

```bash theme={null}
To https://github.com/sid-dev2-kk/test-secret
 + 95ac935...0bb8eb1 main -> main (forced update)
```

## Verify the result on GitHub

* Refresh the repository and inspect older commits that previously contained the secret. The sensitive value should now be replaced by `***REMOVED***` (or the replacement text you specified) across rewritten commits.
* Keep in mind scrubbing Git history does not affect copies of the repository cloned elsewhere, CI logs, or third-party backups. Search for other exposures and rotate credentials where necessary.

## Quick reference — common commands

| Task | Command |
| - | - |
| Install git-filter-repo | `pip3 install git-filter-repo` |
| Clone repo (normal) | `git clone https://github.com/<org>/<repo> cleanup-repo` |
| Clone all refs/tags (mirror) | `git clone --mirror https://github.com/<org>/<repo> cleanup-repo.git` |
| Create replace-file | See `/tmp/mock-expression.txt` example above |
| Run replace-text | `git filter-repo --replace-text /tmp/mock-expression.txt` |
| Force push rewritten history | `git push origin --force --all` and `git push origin --force --tags` |
| Mirror push (mirror clone) | `git push --mirror --force` |

## Links and references

* git-filter-repo GitHub: [https://github.com/newren/git-filter-repo](https://github.com/newren/git-filter-repo)
* GitHub guide to removing sensitive data: [https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository)
* Git official docs: [https://git-scm.com/docs](https://git-scm.com/docs)

Rewriting history changes commit IDs. After a force-push, all collaborators must reclone or reset their local clones to avoid conflicts. Communicate the change clearly and update any CI/CD pipelines or automation that rely on the repository.

## Summary

* Immediately revoke or rotate any compromised secrets before attempting history edits.
* Use `git-filter-repo --replace-text` to remove or replace sensitive strings across all commits.
* Work on a fresh clone (or mirror clone for all refs), force-push the rewritten history, and coordinate with collaborators because history rewriting is disruptive and irreversible for existing clones.

> [card] [Watch Video](https://learn.kodekloud.com/user/courses/github-administration-certification/module/ddb3d739-d57f-4374-b851-69bb14cbeb8b/lesson/473fc43d-8406-49ac-91cb-251c477dbce0)

> [card] [Practice Lab](https://learn.kodekloud.com/user/courses/github-administration-certification/module/ddb3d739-d57f-4374-b851-69bb14cbeb8b/lesson/dd125190-1e55-4a2c-a8a5-13765b1dedaa)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.