Part of the AI coding agent security checklist

An AI agent saw my API key. What now?

Rotate it at the provider first. Cleaning the transcript, the logs and git comes second, and none of it brings the key back.

$ uvx ranwhat clean
Install

Checked against the provider documentation and the ranwhat source listed under Sources. Published .

First Revoke or replace the key at the provider that issued it. Do this before you delete anything.
Then Read the provider's log for use you do not recognise, mask the local transcripts, and clean git only if the key was committed.
Never Treat masking a transcript or rewriting history as the fix. Both leave a working key somewhere.
01 / Scope

Work out where the key went.

An agent that reads a key sends it to the model as part of the conversation, and Claude Code also writes it to disk. Those are two copies, and a third and fourth appear if the key was committed or printed in CI.

Transcript Every tool result is saved in plaintext at ~/.claude/projects/<project>/<session>.jsonl, for 30 days by default. Large outputs go to <session>/tool-results/ beside it.
The model provider Claude Code sends prompts and tool output to the model. Anthropic's data usage page gives 30 days of retention for Team, Enterprise and API use, with zero data retention for qualified accounts. For Free, Pro and Max it is 30 days, or 5 years if you allow your data to be used for model improvement. A transcript you share with /feedback is kept 5 years. Other agents have their own terms; read them.
Git A key in a file the agent wrote, or that you committed after it did, is in history. A pushed commit is also on the remote and in every clone and fork.
Logs CI output, shell history, a pasted bug report, a screenshot, a terminal scrollback. An agent that ran env or cat .env printed the key into whatever captured its output.

To find which transcripts hold it without installing anything, search for a name or the first characters of the value:

grep -rl 'STRIPE_SECRET_KEY' ~/.claude/projects
grep -rl 'sk_live_' ~/.claude/projects
git log --all -S'sk_live_' --oneline        commits whose diff adds or removes it

This guide is written for Claude Code, whose files it describes. Other agents keep their own history, and the steps from section 02 on are the same. Reading the transcripts by hand is covered in Claude Code history, and how the file got read in the first place in Blocking .env reads.

Assume the key is known

You cannot prove who has read a copy you do not control, and a retention window is not a deletion you can check. Treat any value an agent has seen as exposed, and decide what to do about it by what the key can reach, not by how likely a leak seems.

02 / Rotate

Rotate before you clean.

A revoked key is worthless to everyone who holds a copy. Every other step in this guide only shrinks the number of copies.

GitHub's own guidance on leaked secrets says the same: revoke or rotate the secret first, and that alone may solve the problem. Cleaning first costs you time you may not have, and the key keeps working while you do it.

Replace, then revoke, unless it is already abused

Most providers let you create a second key while the first still works, so you can move your applications and switch the old one off without an outage. That is the right order when nothing looks wrong. If the key may already be in someone else's hands, skip the migration: revoke at once, accept the downtime, and put the new key in afterwards. A grace period that keeps the old key alive is also a grace period for whoever else has it.

Give the new key a safer path

Do not paste the replacement into the same chat, and do not leave it in a file the agent can read. Put it in your platform's secret store or an environment variable that is set outside the agent's session, and scope it as narrowly as the provider allows. The token scopes guide shows how to find out what a given token can do.

03 / Providers

Revoke it at the provider.

The steps below come from each provider's current documentation. Menu names move, so if one has changed, the page under Sources will have the new one.

GitHub

Personal access token Profile picture, Settings, Developer settings, then under Personal access tokens choose Fine-grained tokens or Tokens (classic), and click Delete beside the token. Deleting a token that created a deploy key deletes that deploy key too. GitHub's page describes no regenerate step: create a new token, then delete the old one.
OAuth app you authorised Settings, Applications, the Authorized OAuth Apps tab, the app's three-dot menu, then Revoke. Revoke all removes every token for it.
OAuth app you own The REST API revokes one of its tokens with DELETE /applications/{client_id}/token, or every token a user granted with DELETE /applications/{client_id}/grant. Both authenticate as the app. GitHub's pages do not say where to regenerate a client secret, so this guide does not either.

AWS access keys

AWS recommends deactivating before deleting, so you can switch the key back on if something breaks. For a leaked key, do the first two now and the third once you have read the logs in section 04.

aws iam
aws iam update-access-key --access-key-id OLD_KEY_ID --status Inactive --user-name NAME
aws iam create-access-key --user-name NAME      the new key, active at once
aws iam delete-access-key --access-key-id OLD_KEY_ID --user-name NAME

In the console: IAM, Users, the user, Security credentials, then under Access keys choose Actions and Deactivate. A user holds at most two keys. If the leaked value starts with ASIA it is a temporary credential that expires by itself, but its session can still act until it does, so look at what it did.

Google Cloud API keys

Rotate Console, the Credentials page, the key's name, Rotate key. Name the new key, confirm its restrictions, click Create, update your applications, then on the new key's page use Delete the previous key in the Previous key section. Rotation exists only in the console.
Delete gcloud services api-keys delete KEY_ID, with the ID from gcloud services api-keys list. A deleted key can be restored for 30 days, and anyone holding the string can use it again then. Check the list of deleted keys for one you did not delete.

This covers API keys. A service account key file is a different credential with its own steps, which this guide does not cover.

Slack

Bot token auth.revoke revokes a token and needs no scopes. Pass the token itself, as an Authorization header or a POST parameter. For a bot token it deactivates the bot user and removes its channel memberships, but does not uninstall the app. Run the OAuth flow again for a new one.
Token rotation Slack's app-level tokens do not expire by default, so a leaked one stays valid until you act. Token rotation, available to granular bot apps, makes access tokens short-lived. Slack's page does not say that turning it on revokes a token that has already leaked, so revoke that one yourself.

Stripe

Dashboard, API keys, the key's overflow menu, Rotate key. The old key keeps working for up to 7 days unless you set Expiration to Now, which deletes it at once. For a leaked key choose Now. If you would rather have no replacement yet, Expire key stops the key and creates nothing. Use View request logs on the same menu before you rotate, so you can see what the key did.

OpenAI and Anthropic

Anthropic Claude Console, the API keys page from the profile menu, the three-dot menu beside the key, Delete API Key. Anthropic's support article recommends revoking a suspected key immediately. It also says GitHub scans public repositories for Claude API keys and that Anthropic deactivates a key GitHub reports, which helps only if the key reached a public repository.
Admin API An organisation admin can deactivate a key without deleting it by updating its status to inactive in the Admin API.
OpenAI The API keys page of the dashboard, then delete the key. OpenAI's help article describes the delete control on that page as a trash can icon, and says a deleted key cannot be used. Keys tied to a project are listed under that project.

Anything else

Use the issuing provider's own console and its own documentation. If you are not sure which provider a value belongs to, section 05 shows how ranwhat clean labels what it finds.

04 / Audit

Check whether someone else used it.

Revoking stops the next request. It does not tell you about the ones before. Ask the provider for its record of the key, starting at the time the agent read it.

AWS Last-used data first, then CloudTrail. Event history keeps 90 days of management events per Region, free, and a lookup can filter on an access key ID. It shows management events only, not data events such as S3 object reads, and a search covers one Region at a time, so run it in each Region you use.
GitHub Settings, Security log, in the Archives section. It lists 90 days of activity, and fine-grained token activity falls under personal_access_token and OAuth under oauth_access. You can export results as JSON or CSV. GitHub's page does not say where to see when a classic token was last used.
Stripe View request logs on the key's menu opens Workbench's request logs for that key. Look for calls you did not make, such as refunds, payouts, new keys or new webhook endpoints.
Others Usage dashboards for OpenAI and Anthropic show spend and requests per key or project. Look for a spike, or traffic from a model or region you do not use. This guide has not verified an audit-log feature for Google Cloud API keys or for Slack tokens, so check those providers' documentation for one.
aws
aws iam get-access-key-last-used --access-key-id OLD_KEY_ID
aws cloudtrail lookup-events --region us-east-1 \
  --lookup-attributes AttributeKey=AccessKeyId,AttributeValue=OLD_KEY_ID

The last-used call reports the date, service and Region of the most recent request. It is a hint, not a full history, so read the CloudTrail events for the whole picture. If you find use you cannot explain, the problem is bigger than a key: look for what it created, such as new users, keys, roles, instances and webhooks, and remove those too.

05 / Mask

Mask the key in the local transcripts.

With the key dead, remove the plaintext copy so an infostealer, a backup or the next agent does not find it.

ranwhat clean reads the transcripts for secrets and reports each distinct one with the project it was in and, when the transcript names it, the file it came from. A bare run changes nothing, and opens a review session where rotate lists what to rotate, grouped by provider.

$ uvx ranwhat clean

When the list looks right, mask it. --apply masks everything it found without asking, and mask 3 in the review masks one finding. --days N widens the window past the default 30 days.

uvx ranwhat clean --apply            mask what it found, backups first
uvx ranwhat clean --apply --days 90  look back further
Backups Before it rewrites a transcript, clean copies the original to ~/.ranwhat/backups, readable by you alone. Those copies still hold the key. Delete the folder once the result looks right.
Safe write It parses the rewritten file back before replacing the original. It leaves a file alone if something wrote to it in the last two minutes, so close the session first and run it again if one is skipped.
Not read It does not read the tool-results/ folders yet, so search them yourself with grep -rl and delete or edit the files by hand.

Masking is not remediation

ranwhat clean does not revoke the key. It does not touch what the model provider kept, your git history, a CI log or a clipboard. It only stops the transcript on this machine from leaking the value a second time. That is useful, and it is the smallest step in this guide.

06 / Git

Clean git only if it was committed.

If the key never reached a commit, skip this section. If it did, rotation is still what protects you, and a rewrite is housekeeping.

History rewriting does not un-leak a pushed secret

GitHub's documentation says that if you only rewrite history and force-push, the commits with the sensitive data may still be accessible elsewhere: in clones, in forks, in cached views and through pull requests that reference them. Once a commit has been pushed, assume someone has it.

Find it

git log --all -S'THE_KEY_VALUE' --oneline   commits that add or remove the string
git log --all --oneline -- path/to/.env       commits that touched a file

The first command puts the full key in your shell history. Search for a prefix instead if that matters.

Rewrite it

GitHub documents git filter-repo, version 2.47 or later, with its --sensitive-data-removal flag. Run it in a fresh clone:

git-filter-repo --sensitive-data-removal --invert-paths --path PATH-TO-FILE
git-filter-repo --sensitive-data-removal --replace-text ../passwords.txt
git push --force --mirror origin

The first removes a file from all history, using its full path and again for each old location if it was moved. The second replaces the text listed in a file. Pushes to refs/pull/* fail, because GitHub treats those refs as read-only.

Clones You cannot clean your colleagues' clones. Send them instructions to rebase rather than merge, since a merge can bring the old history back.
Forks Commits stay reachable in forks. You have to ask each owner to remove them or delete the fork.
GitHub Support Support can dereference or delete affected pull requests, remove cached views and references, and run server-side garbage collection. GitHub says it helps with sensitive data only when the risk cannot be mitigated by rotating the credentials, which is one more reason to rotate first.
Cost Every commit hash changes, signatures are lost and open pull requests can break. Merge or close them first.
07 / Prevent

Make a repeat harmless.

Keep the key out of the agent's reach, catch it before it is pushed, and make it short-lived so a leak expires.

Deny rules Read(./.env) style rules keep the agent's file tools and the common file commands away from a secrets file. They do not stop grep -r or a script that opens the file itself. The sandbox closes that gap. Blocking .env reads has the rules and the sandbox settings.
Secret scanning On GitHub, secret scanning runs automatically and for free on public repositories. It scans history on all branches, plus issues, pull requests, discussions and wikis, and raises an alert that says to rotate. Push protection blocks a push that contains a secret before it reaches the repository; the repository-level version needs GitHub Secret Protection.
Short-lived credentials Give an agent a token that expires, not a key that lives for years. Stripe restricted keys, AWS temporary credentials and Slack token rotation all shrink what a stolen copy is worth. Stripe also lets you attach an access policy that limits a key to known IP addresses, so a copy used from elsewhere is blocked.
Narrow scope A key that can only read one thing is a smaller incident. Token scopes covers how to give an agent less.
Less on disk Lower cleanupPeriodDays so mistakes age out sooner, and check your machine as a whole with the developer OPSEC guide.

uvx ranwhat check runs the secret search and the action log together and changes nothing, so you can run it after each long session. The rest of the checklist is in AI coding agent security.