AWS access key leaked: what to do in the first 10 minutes
An AKIA… access key ID and its secret went somewhere they should not have: a public GitHub push, a Slack message, a screenshot, a Docker image, a shell history file. It is widely reported that scrapers find keys in public repositories within minutes, so treat it as already stolen. Work through this list in order. Step 1 is the only one that has to happen right now; the rest is the next ten minutes.
1. Deactivate the key. Do not delete it yet
An inactive key is refused on every request immediately, and the change is reversible. Deleting is permanent, and it removes the key ID you are about to search CloudTrail for. AWS's own rotation procedure deactivates first and deletes later, and this is the one time you should not wait for the "last used" check before doing it.
First confirm which account the key belongs to. This works with any identity and tells you whether to panic about this account or a different one:
aws sts get-access-key-info --access-key-id AKIAIOSFODNN7EXAMPLE
Then deactivate it using credentials that are not the leaked key. If the leaked key is the one your CLI profile uses, do this step in the console or with a different profile:
aws iam list-access-keys --user-name NAME
aws iam update-access-key --user-name NAME --access-key-id AKIAIOSFODNN7EXAMPLE --status Inactive
In the console: IAM, Users, choose the user, Security credentials tab, Access keys, then Actions and Deactivate. A root user key is managed from the root user's own Security credentials page, and should be deleted rather than rotated.
A key starting with ASIA is a temporary credential and expires on its own. To cut it off early, use the role's Revoke sessions tab in the IAM console; see Revoke IAM role temporary security credentials.
2. See whether it was used
Quick answer first. This shows the last date, service and Region the key signed a request for, and it still works on an inactive key:
aws iam get-access-key-last-used --access-key-id AKIAIOSFODNN7EXAMPLE
A last-used date before the leak is good news but not proof. For the real record, open the CloudTrail console, choose Event history, set the lookup attribute to AWS access key and paste the key ID. Three limits of event history matter here, all from the CloudTrail docs:
- It is per Region. Attackers often work in Regions you never use, so repeat the search in each one, starting with
us-east-1, where events from global services such as IAM are logged. - The default filter hides read-only events. Clear it, because reconnaissance such as
GetCallerIdentity,ListBucketsandListUsersis exactly what a stolen key does first. - It covers the last 90 days of management events only. Data events (S3 object reads, for example) only appear if you already had a trail or event data store logging them.
From the CLI, one Region at a time:
aws cloudtrail lookup-events --region us-east-1 \
--lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIAIOSFODNN7EXAMPLE \
--query 'Events[].[EventTime,EventName,EventSource]' --output table
Look for anything the key created: CreateUser, CreateAccessKey, CreateLoginProfile, AttachUserPolicy, CreateRole, RunInstances, RequestSpotInstances, and SES or Bedrock calls. Then check the Billing console for a cost spike.
3. Undo what the key created
Deactivating the key does nothing to the extra user, access key or role an attacker made with it; those are the real persistence. For every creation event you found in step 2, delete what it created, and check that no new policy was attached to your own users or roles. A quick inventory:
aws iam list-users
aws iam list-access-keys --user-name NAME
aws iam list-roles --query 'Roles[?starts_with(CreateDate, `2026-10`)].[RoleName,CreateDate]'
Adjust the date prefix to the leak window. If the key had admin rights and you find any of this, assume there is more and open a support case.
4. Rotate, then delete
Create a replacement, switch everything that used the old key, confirm it works, and only then delete the leaked one. Each IAM user can hold at most two access keys, so if the user already had two, deleting the inactive leaked key is how you make room:
aws iam create-access-key --user-name NAME
# update ~/.aws/credentials, CI secrets, .env files, deploy configs
aws iam delete-access-key --user-name NAME --access-key-id AKIAIOSFODNN7EXAMPLE
Ask whether the replacement needs to be a long-term key at all. The IAM docs are blunt about it: prefer roles and temporary credentials, which expire on their own. For a laptop, that usually means IAM Identity Center and aws sso login instead of an AKIA key in ~/.aws/credentials.
5. What AWS and GitHub may already have done
If the key went to a public GitHub repository, you may find a support case and an email from AWS waiting. GitHub runs secret scanning on every public repository, Amazon AWS is a secret scanning partner, and matches of partner patterns in public code are sent to the provider. AWS responds by attaching the managed policy AWSCompromisedKeyQuarantineV3 to the user and opening a case. Three things about that policy:
- It does not deactivate the key. It denies a list of expensive or dangerous actions (
ec2:RunInstances,iam:CreateUser,iam:CreateAccessKey,s3:GetObject, Bedrock and SES calls, and dozens more) while leaving existing resources alone. Step 1 is still on you. - It denies
iam:UpdateAccessKey,iam:DeleteAccessKeyandcloudtrail:LookupEventsfor the quarantined user. If you try to clean up as that user, steps 1 and 2 fail with AccessDenied. Use an administrator identity. - AWS's description says: "Do NOT remove this policy. Instead, please follow the instructions specified in the support case created for you." Finish the steps above, reply on the case, and let AWS lift it.
Push protection would have refused the push in the first place; the AWS key pattern supports it. Turning it on is in GitHub push protection blocked your push.
6. Clean up the copies
The key is dead, so this is tidying, but dead keys keep tripping scanners and get pasted back into use. ~/.aws/credentials is plain text; edit the stale entry out. If you ran export AWS_SECRET_ACCESS_KEY=… in a terminal, it is in .zsh_history, .bash_history or fish history. If it was committed, see how to remove an API key from git history; if it was baked into an image, see secrets in Docker images. The general checklist for other providers is in I leaked my API key, what do I do?