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

# How to respond to an exposed credential

> What to do after committing an API key, AWS secret, or database password to git — rotate the credential, remove it from code, and purge it from history.

<Warning>
  If you committed a credential and then removed it in a later commit, it is still exposed. Anyone who has cloned the repository can read it from git history. Rotation is mandatory.
</Warning>

This guide covers what to do when BattleTest flags a committed secret, or when you discover one yourself. The steps apply to any credential: AWS access keys, API tokens, database passwords, private keys, or service account credentials.

## Step 1: Rotate the credential immediately

Before anything else, revoke the exposed credential and issue a new one. Do this now, before touching git history — if the key has been in a public or shared repository, assume it has already been read.

| Credential type              | Where to rotate                                                 |
| ---------------------------- | --------------------------------------------------------------- |
| AWS access key               | IAM → Users → Security credentials → Make inactive → Create new |
| GitHub personal access token | Settings → Developer settings → Personal access tokens → Revoke |
| Stripe API key               | Dashboard → Developers → API keys → Roll secret key             |
| SendGrid API key             | Settings → API Keys → Revoke                                    |
| Database password            | Your database admin panel or `ALTER USER` command               |
| Other SaaS API key           | Check the service's security or developer settings              |

After rotation, update the new credential in your deployment secrets manager (environment variables, Vault, AWS Secrets Manager, etc.) — not in code.

## Step 2: Remove the credential from current code

If the credential is still in your codebase (not just in history), remove it:

1. Find all occurrences: `grep -r "AKIAIOSFODNN7EXAMPLE" .` (use your actual key prefix)
2. Replace with an environment variable reference: `process.env.AWS_ACCESS_KEY_ID`
3. Add the secret to your secrets manager or `.env` file (not committed)
4. Add `.env` to `.gitignore` if it isn't already

Commit the removal.

## Step 3: Purge the credential from git history

Removing a secret from current code doesn't remove it from git history. You need to rewrite history.

**Option A: `git filter-repo` (recommended)**

```bash theme={null}
# Install
pip install git-filter-repo

# Remove the file that contained the secret
git filter-repo --path path/to/secret/file --invert-paths

# Or replace the secret string everywhere in history
git filter-repo --replace-text <(echo 'ACTUAL_SECRET_VALUE==>REDACTED')
```

**Option B: BFG Repo Cleaner (faster for large repos)**

```bash theme={null}
# Download BFG from https://rtyley.github.io/bfg-repo-cleaner/

# Create a file listing secrets to remove
echo 'AKIAIOSFODNN7EXAMPLE' > secrets.txt

# Run BFG
java -jar bfg.jar --replace-text secrets.txt your-repo.git

# Clean up
cd your-repo
git reflog expire --expire=now --all && git gc --prune=now --aggressive
```

Both tools rewrite every commit in your history that contained the secret.

## Step 4: Force-push to the remote

After rewriting history locally, push the rewritten history to the remote:

```bash theme={null}
git push --force --all
git push --force --tags
```

<Warning>
  Force-pushing rewrites the shared history for everyone who has cloned the repository. Anyone with a local clone will need to re-clone or run `git fetch --all && git reset --hard origin/main`.
</Warning>

If this is an organisation repository with branch protection rules preventing force-push, you'll need to temporarily disable protection rules or coordinate with an admin.

## Step 5: Notify anyone who has access to the repository

If the repository is or was public, or if it's a shared private repository, assume the credential has been seen. Notify your team that they need to re-clone and that the old credential is revoked.

If the key had write or admin access to a production system, check your audit logs for unexpected activity during the period the key was exposed.

## Step 6: Prevent recurrence

BattleTest's secret scanning runs against the full commit history of every PR branch — not just the diff — so it catches secrets that were committed and then "removed" before the PR was opened.

To avoid future incidents:

* **Use environment variables.** Never hardcode credentials, even in config files committed to a private repo.
* **Add pre-commit hooks.** Tools like [`detect-secrets`](https://github.com/Yelp/detect-secrets) or [`gitleaks`](https://github.com/gitleaks/gitleaks) can prevent secrets from being committed in the first place.
* **Connect BattleTest to your repositories.** Every PR gets scanned automatically. See [Get your first PR security review](/docs/tutorials/quick-start).

<Note>
  BattleTest scans the **full commit history** of every PR branch, not just the diff — so a secret that was committed and later "removed" is still caught. For how secret scanning works, see [How PR review works](/docs/concepts/how-pr-review-works#secret-scanning). To dismiss a secret found in a test fixture, see [How to review, dismiss, and track findings](/docs/how-to/manage-findings#dismiss-a-false-positive).
</Note>
