When AWS finds an IAM user's access key exposed in public, it attaches the AWSCompromisedKeyQuarantineV3 managed policy to that user, opens a support case and leaves the owner to work out what just broke and what to do next. This guide is the owner's runbook for that moment: what the policy denies, why detaching it to restore an application is the wrong first move, how to investigate and rotate, and when the policy can come off. It is for cloud engineers, platform owners and on-call responders who received the AWS email or saw the policy appear on a user. It stays specific to the quarantine policy: the wider response sequence for any leaked cloud key is in the Cloud Access Key Leak Playbook, and key hygiene is in the AWS Access Keys Security Guide.
This is an independent guide from NHI Mgmt Group, based on AWS's public documentation as of November 2026. It is not sponsored or reviewed by AWS. Product features change, so confirm settings against AWS's current documentation.
Key takeaways
- The policy is a brake, not a fix: AWS describes AWSCompromisedKeyQuarantineV3 as a deny-only policy that limits fraud and unauthorised charges "while not impacting the existing resources". The exposed key still works for every action the policy does not list.
- Do not detach it to get an application running: the policy text itself says not to remove it and to follow the support case. Move the application to a new credential instead, then retire the exposed key.
- The quarantined user cannot clean up after itself: the policy denies
iam:DeleteAccessKey,iam:UpdateAccessKey,iam:DetachUserPolicyandcloudtrail:LookupEventsfor that user, so the response has to run from a separate administrator or incident role. - Assume the key was used before AWS caught it: check CloudTrail in every Region for new users, keys, roles, policies, instances, Lambda functions and Bedrock calls from the exposure window, not just the last hour.
- Close the loop with AWS: reply in the support case with what you did. The safest end state is a deleted key and, where possible, a deleted IAM user replaced by a role.
When you need this
- You received an AWS email or support case about an exposed or compromised access key, naming an IAM user and a key ID starting
AKIA. - An AWS Health event fired: AWS's own sample automation describes how AWS monitors popular code repositories for exposed access keys and raises an
AWS_RISK_CREDENTIALS_EXPOSEDevent, while temporarily restricting the API calls the key can make. - An application started failing with AccessDenied on calls such as
s3:GetObject,logs:PutLogEventsorecr:GetAuthorizationToken, and the denial names an explicit deny in an identity-based policy. - A user shows an unfamiliar AWS managed policy named AWSCompromisedKeyQuarantineV3 (or the older AWSCompromisedKeyQuarantineV2) in the IAM console, or CloudTrail shows an
AttachUserPolicyevent you did not make.
If the key was found by your own secret scanning rather than by AWS, the same steps apply, but the policy will not be there to slow an attacker down: contain faster. For repository alerts see How to respond to a GitHub secret scanning alert.
What the quarantine policy denies
AWS publishes the policy document on its managed policy reference page. As checked in November 2026, AWSCompromisedKeyQuarantineV3 was created on 21 August 2024, its default version was v4, and it had last been edited on 9 November 2026. AWS edits the action list over time, so read the current version on the reference page during an incident rather than relying on a copy. The actions fall into clear groups:
| Group | Examples of denied actions | Why AWS blocks them |
|---|---|---|
| Identity persistence | iam:CreateUser, iam:CreateAccessKey, iam:CreateLoginProfile, iam:CreateRole, iam:AttachUserPolicy, iam:PutRolePolicy, iam:UpdateAssumeRolePolicy, iam:PassRole, iam:CreateServiceSpecificCredential | Stops the attacker creating new identities, keys or trust that would survive rotation |
| Self-protection of the quarantine | iam:DetachUserPolicy, iam:UpdateAccessKey, iam:DeleteAccessKey, iam:UpdateUser, iam:ListUsers | Stops the exposed key removing the policy or tampering with keys and users |
| Compute for profit | ec2:RunInstances, ec2:StartInstances, ec2:RequestSpotInstances, reserved instance purchases, lightsail:Create*, ecs:CreateService, lambda:CreateFunction, sagemaker:CreateProcessingJob, codebuild:CreateProject, glue:CreateJob | Limits resource hijacking and unexpected charges |
| Generative AI use | bedrock:InvokeModel, bedrock:InvokeModelWithResponseStream, bedrock:CreateModelInvocationJob, bedrock:CallWithBearerToken, several bedrock-mantle actions | Limits model invocation billed to your account |
| Data access and destruction | s3:GetObject, s3:ListBucket, s3:ListAllMyBuckets, s3:DeleteObject, s3:DeleteBucket, s3:PutBucketPolicy, s3:PutBucketAcl, s3:PutAccountPublicAccessBlock | Limits data theft, deletion and making buckets public |
| Keys and logs | kms:ScheduleKeyDeletion, kms:PutKeyPolicy, kms:RevokeGrant, kms:CreateGrant (unless via an AWS service), logs:PutLogEvents, cloudtrail:LookupEvents | Limits destructive key changes and reconnaissance of your audit trail |
| Account and organisation | organizations:CreateAccount, organizations:LeaveOrganization, organizations:InviteAccountToOrganization, savingsplans:CreateSavingsPlan | Limits account-level fraud |
| Temporary credentials | sts:GetSessionToken, sts:GetFederationToken | Stops the key minting session credentials that would outlive key deletion |
| Email and messaging probes | ses:GetSendQuota, ses:ListIdentities, sns:GetSMSAttributes | Limits checks for spam-sending capacity |
Two points matter for responders. First, the policy is attached to the user, so it restricts only that user's own requests. An administrator using a different principal can still deactivate the key, delete it and manage the policy. Second, anything not in the list still works. If the user had, for example, dynamodb:*, secretsmanager:GetSecretValue or sts:AssumeRole on a privileged role, the exposed key can still do those things until it is deactivated. Check what the user can assume: role sessions obtained before the key is disabled are not stopped by disabling the key.
Why not just detach it
The usual pressure is an outage: an integration that reads S3 or ships logs stops working, and the fastest way to restore it looks like removing the policy. That restores the attacker's full permissions along with the application's. AWS's policy description is explicit: do not remove the policy, follow the support case instead.
| Option | Restores the application | Effect on the attacker | Use when |
|---|---|---|---|
| Detach the policy, keep the key | Yes, immediately | Full permissions restored to a public key | Never |
| Leave policy, rotate to a new key on the same user | Yes, once the new key is deployed | Exposed key disabled; quarantine stays as a backstop until you clear it | The workload genuinely needs a long-term key, for example an on-premises system without a federation path |
| Leave policy, move the workload to an IAM role | Yes, once the role is wired in | Exposed key and, later, the user removed entirely | Workloads on EC2, ECS, EKS, Lambda or CI systems that support federation; the preferred end state |
| Accept the outage until investigation ends | No | Exposed key disabled | Evidence of malicious use, or the user has broad permissions you cannot quickly reason about |
The rotation path needs an administrator to create the new key, because the quarantine denies iam:CreateAccessKey to the user itself. AWS also limits each IAM user to two access keys, so if the user already has two, deactivate the exposed one first.
Before you start
- Use a separate principal: an administrator or break-glass incident role in the affected account, not the quarantined user or any credential on the same machine as the leak.
- Open the support case: AWS's policy text points to "the support case created for you". Read its instructions first; they may name the key, the exposure location and the time AWS detected it.
- Record the facts: account ID, IAM user name, access key ID, where the key was exposed (repository, commit, paste, image), the earliest possible exposure time and the time AWS attached the policy (the
AttachUserPolicyevent in CloudTrail). - Find the owner: who or what uses this user. Check tags, the
Last usedservice and Region on the key, and the user's policies. See How to assign owners to orphaned service accounts if nobody claims it. - Preserve evidence: do not delete resources until you have recorded them. AWS's compromise guidance says to back up what you need for investigation, for example an EBS snapshot before terminating an instance.
Step-by-step
1. Contain the exposed key (first 30 minutes)
- From your administrator principal, deactivate the exposed key:
aws iam update-access-key --user-name USER --access-key-id AKIA... --status Inactive. Deactivation is reversible, deletion is not, so deactivate first while you collect evidence. - Remove the secret from wherever it was exposed, then treat the source as burned: history rewrites and forks mean the key must be considered public forever. See the Leaked Credential Response Playbook for the source-side steps.
- Leave AWSCompromisedKeyQuarantineV3 attached. It now also covers any second key on the user while you investigate.
- If the user can assume roles, list them from its policies and check CloudTrail for
AssumeRolecalls by the key. For any role it assumed, use Revoke active sessions on the role's Revoke sessions tab. AWS documents that this attaches an inlineAWSRevokeOlderSessionspolicy that denies all actions to sessions issued before the revocation time, and warns that it affects every user of the role.
2. Restore the workload on a new credential
- Decide the target from the table above. Prefer an IAM role: instance profile, ECS task role, EKS pod identity or IRSA, Lambda execution role, or OIDC federation for CI. See AWS IAM Roles vs IAM Users.
- If a key is unavoidable, create one from the administrator principal with
aws iam create-access-key --user-name USER, store it in a secrets manager rather than a file, and deploy it. - Right-size permissions while you are here: use the user's last accessed information to remove services it never calls. See How to find unused AWS IAM roles and access keys.
- Confirm the application works on the new credential before you go further.
3. Investigate what the key did
AWS's compromise guidance lists the sources: credential reports, IAM last accessed information, CloudTrail event history, and cost and usage data. Work through them for the window from earliest exposure to deactivation.
| Question | Where to look | What indicates misuse |
|---|---|---|
| Was the key used, from where? | aws iam get-access-key-last-used; CloudTrail filtered on the access key ID | Calls from IP addresses, user agents or Regions the workload never uses |
| Did it create persistence? | CloudTrail CreateUser, CreateAccessKey, CreateLoginProfile, CreateRole, AttachUserPolicy, PutUserPolicy, UpdateAssumeRolePolicy | Any of these by the key, especially before the quarantine time |
| Did it reach other identities? | CloudTrail AssumeRole, GetSessionToken, GetFederationToken; ASIA keys whose sessionIssuer traces back to this user | Temporary credentials still active after the key was disabled |
| Did it spend money? | Cost Explorer by service and Region; CloudTrail RunInstances, CreateFunction, InvokeModel | New compute, Lambda or Bedrock usage in Regions you do not use |
| Did it touch data? | CloudTrail data events for S3 and other services, if enabled; S3 server access logs | GetObject volume or ListBucket across buckets the workload does not need |
| Did it weaken controls? | CloudTrail PutBucketPolicy, PutBucketAcl, StopLogging, DeleteTrail, KMS key policy changes, GuardDuty or Config changes | Any change to logging, encryption or public access |
Check every Region, not only the ones you use: AWS's guidance says so explicitly, because hijacked compute is often launched where nobody looks. CloudTrail event history covers management events for the last 90 days; data events appear only if you configured a trail to record them. See the AWS CloudTrail Guide, and the Amazon GuardDuty Guide for related findings.
4. Eradicate
- Delete any user, key, role, policy version or trust change the attacker created. Record each before deleting.
- Terminate unauthorised resources in every Region after taking the snapshots you need for evidence.
- Delete the exposed key once the new credential is proven:
aws iam delete-access-key --user-name USER --access-key-id AKIA.... - If the workload moved to a role, delete the IAM user altogether. Deleting a user through the API or CLI requires removing its keys, policies and group memberships first, so the quarantine policy is detached as part of that deletion, from your administrator principal, once the case allows it.
5. Clear the quarantine and close the case
- Reply in the AWS Support case with what you did: key deactivated and deleted, resources removed, investigation result. AWS's compromise guidance asks for exactly this confirmation.
- If the user must stay, follow the support case instructions on removing the policy. Detach it only from an administrator principal, only after the exposed key is deleted and the investigation is closed, and record who did it and why.
- Confirm the account's root user email and contacts are correct and that root has MFA, as AWS's compromise checklist also asks.
Verify it worked
- Key state:
aws iam list-access-keys --user-name USERshows no exposed key ID; if the user remains, only the new key is active. - No orphaned sessions: no CloudTrail activity from the exposed key ID, or from temporary credentials it issued, after the deactivation time.
- Workload healthy: the application runs without AccessDenied errors on its new credential or role.
- Clean account: no unexplained users, keys, roles, instances or functions in any Region, and the next bill shows no unexplained services.
- Case closed: the support case is resolved and the incident record lists every step with its time.
Rollback and common errors
| Symptom | Cause | Fix |
|---|---|---|
| AccessDenied with "explicit deny in an identity-based policy" after rotating | The new key is on the same quarantined user and the call is in the deny list | Move the workload to a role, or keep it degraded until the case allows clearing the policy; do not detach early |
| Administrator cannot delete the key | The administrator is signed in as the quarantined user or a credential with the same restriction | Use a separate administrator or incident role |
| An application broke after deactivation that nobody knew about | A second consumer of the same key | Reactivate only if the exposure risk is accepted for minutes, not days; better, issue it its own credential |
| Cannot create a new key | User already has two keys | Deactivate and delete the exposed one first |
| Activity continues after the key is disabled | Role sessions or session tokens issued earlier | Revoke role sessions and check for attacker-created users or keys |
Common failure patterns
- Detaching the policy to fix production: it returns every permission to a public key. Fix production with a new credential.
- Stopping at rotation: deleting the key without searching CloudTrail misses the user or role the attacker created in the minutes before AWS reacted.
- Checking only your Regions: unauthorised instances in an unused Region keep running and billing.
- Re-leaking the replacement: putting the new key back into the same repository, image or config file that leaked the first one.
- Ignoring the second key: a user with two keys where only one is reported; check both and their last used dates.
- Leaving the user in place: a quarantined user that survives the incident with the same broad policies and no owner is the next exposure.
Hardening afterwards
- Remove long-term keys where you can: roles and federation leave nothing static to leak. See the AWS Access Keys Security Guide.
- Alert on the quarantine itself: build an EventBridge rule for the
AWS_RISK_CREDENTIALS_EXPOSEDHealth event and for CloudTrailAttachUserPolicyevents that attach AWSCompromisedKeyQuarantineV3 or V2, routed to the owning team and the SOC. - Block leaks at commit: push protection stops keys before they become public. See How to enable GitHub secret scanning push protection.
- Bound what a key can do: least privilege, permissions boundaries and network conditions shrink the damage of the next leak. See the AWS IAM Permissions Boundaries Guide.
Detection and measurement
- Time to deactivate: minutes from the AWS notification to the exposed key being inactive. Target under one hour.
- Quarantine removals without a closed case: count of
DetachUserPolicyevents for the quarantine policy before the incident is closed. Target zero. - Repeat exposures: quarantine events per quarter, and how many hit the same team or repository twice.
- IAM users with active keys: trend downward as workloads move to roles.
- Investigation completeness: share of quarantine incidents with an all-Region CloudTrail and cost review recorded.
Framework mapping
| Framework | Reference | How it applies |
|---|---|---|
| MITRE ATT&CK | T1552.001 Credentials In Files | How most exposed keys are found |
| MITRE ATT&CK | T1078.004 Cloud Accounts | Use of the exposed key |
| MITRE ATT&CK | T1098.001 Additional Cloud Credentials | New keys created for persistence, which the policy denies |
| MITRE ATT&CK | T1496.001 Compute Hijacking | Instance and function launches the policy denies |
| NIST SP 800-53 Rev. 5 | IR-4 Incident Handling; IA-5 Authenticator Management; AC-2 Account Management; AU-6 Audit Record Review | Containment, rotation, user retirement and CloudTrail review |
| NIST CSF 2.0 | RS.MI-01; RS.AN-03; PR.AA-01 | Contain, analyse root cause, manage credentials |
Practitioner checklist
- Work from a separate administrator or incident role, never the quarantined user.
- Read the AWS support case and record key ID, user, exposure source and times.
- Deactivate the exposed key and leave AWSCompromisedKeyQuarantineV3 attached.
- Revoke sessions on any role the key assumed.
- Restore the workload on a role or a new stored key, not by detaching the policy.
- Review CloudTrail, credential reports and costs in every Region for the exposure window.
- Remove attacker-created identities and resources after capturing evidence.
- Delete the exposed key, and the user if the workload moved to a role.
- Reply in the support case and clear the policy only as it instructs.
- Add alerting on the Health event and on quarantine policy attachment.
Standards and references
- AWS: AWSCompromisedKeyQuarantineV3 managed policy reference
- AWS: AWSCompromisedKeyQuarantineV2 managed policy reference
- AWS re:Post Knowledge Center: What do I do if I notice unauthorized activity in my AWS account?
- AWS: Update access keys
- AWS: Revoke IAM role temporary security credentials
- AWS: Remediating potentially compromised AWS credentials (GuardDuty)
- AWS: aws-health-tools, AWS_RISK_CREDENTIALS_EXPOSED automated action
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls
Related NHI Mgmt Group resources: Cloud Access Key Leak Playbook, Leaked Credential Response Playbook, AWS Access Keys Security Guide, AWS IAM Roles vs IAM Users.