P.K. SHARMA

Cyber security intelligence, AI governance, practitioner analysis

AWS quarantines a leaked access key in 10 seconds, but the key keeps working for anything not on the deny list

Unit 42 timed AWS attaching its compromised-key quarantine policy 10 seconds after a key hit public GitHub. The key stays valid, the policy denies a fixed list of 99 actions, and role pivots, secret reads and clean-up are left to the customer.

By Parminder Kumar Sharma · · 16 min read

Editorial illustration for the briefing: AWS quarantines a leaked access key in 10 seconds, but the key keeps working for anything not on the deny list

Ten seconds to quarantine, and a key that still works

In a test run by Palo Alto Networks' Unit 42 on 19 December 2025, an AWS access key and its secret were pushed to a public GitHub repository at 18:50:05 UTC. At 18:50:15, CloudTrail recorded AWS attaching the managed policy AWSCompromisedKeyQuarantineV3 to the IAM user that owned the key. That is 10 seconds from exposure to what AWS's own email calls the "Quarantine Policy". A support case followed at 18:50:59, 54 seconds after the push. Unit 42 published the full timeline on 21 September 2026 in From Exposure to Lockdown.

Ten seconds is fast, and the automation is real. But be clear about what the number does not show. It comes from one test, one key, one public repository and one push to the main branch. It says nothing about how quickly an attacker who scrapes GitHub would have used the key in those 10 seconds. It says nothing about keys leaked anywhere AWS is not told about. Most of all, it does not mean the key stopped working. AWS did not disable the key. It attached a deny list to the user, and anything not on that list still works if the user's own policies allow it.

Timeline of the Unit 42 test on 19 December 2025: key pushed to public GitHub at 18:50:05 UTC; quarantine policy attached at 10 seconds; GitHub email at 11; AWS Health alert at 12; AWS email at 21; support case at 54. The key had full permissions for 10 seconds, then stayed valid with 99 actions denied. Panels list what the policy denies, actions it does not list, and steps left to the customer. AWS does not disable the key.
Timeline drawn from Unit 42's test log (times UTC) and screenshots; policy contents from the AWS Managed Policy Reference for AWSCompromisedKeyQuarantineV3, accessed 21 September 2026.

This briefing sets out what AWS does automatically, what Unit 42 measured, what the current policy blocks, what it leaves open to an attacker holding the key, and what the account owner still has to do. It also flags one thing Unit 42's write-up does not cover: AWS changed the V3 policy again on 16 March 2026, adding KMS, S3 encryption and AWS Organizations actions to the deny list. The version in force today is not the one Unit 42 describes.

What AWS does automatically, second by second

The trigger in Unit 42's test was GitHub's secret scanning partner programme. GitHub scans public repositories and public npm packages for known credential formats and, when it finds one belonging to a partner, sends the match to that partner's endpoint. AWS is one of those partners. Unit 42 says AWS also acts on "other notices" of exposure, but neither Unit 42 nor AWS lists which other sources trigger the process.

The key was not pushed by accident. At 18:46:57, GitHub push protection flagged both the access key and the secret and asked whether the push was deliberate. The tester allowed it, and the push succeeded at 18:50:05, 3 minutes 8 seconds later. Everything below is measured from that successful push.

Unit 42 exposure test, 19 December 2025, times in UTC. Seconds after the push are computed by pk-sharma.com from Unit 42's timestamps.

Time (UTC)EventSeconds after pushIn default CloudTrail?
17:29:44Access key created for TestUsern/a (1 h 20 min 21 s before)Yes, CreateAccessKey
18:46:57GitHub push protection warns; tester allows pushn/a (3 min 8 s before)No
18:50:05Key and secret land in public repo0No
18:50:15AWSCompromisedKeyQuarantineV3 attached to TestUser10Yes, AttachUserPolicy
18:50:16GitHub email about the detected secret11No
18:50:17AWS Health alert "Risk IAM quarantine"12No
18:50:26AWS email: key exposed, Quarantine Policy applied21No
18:50:59AWS Support case opened54No

Three details in Unit 42's screenshots matter for anyone who has to detect this.

The CloudTrail record names your user, not AWS. The AttachUserPolicy event lists TestUser in the userIdentity field, with a temporary ASIA access key ID, even though TestUser did nothing. Unit 42's text says the record did not indicate an automated AWS action. Its screenshot of the same record does show invokedBy, sourceIPAddress and userAgent all set to "AWS Internal". Either way, the reliable signal is the policyArn request parameter, which contains AWSCompromisedKeyQuarantineV3. The event was logged in us-east-1.

The Health alert and the support case leave no CloudTrail trace. The Health event sits under the service "Risk", marked "Action Required", for the personas "Operations, Security". Its end time is 2 January 2026, 14 days after it opened. The support case is titled "[Action Required] Your AWS Access Key is Exposed for AWS Account", with severity "Urgent business impacting question" and status "Pending customer action".

The email goes wherever the account's contacts point. Unit 42 notes that in some organisations the cloud engineering team reads these emails and the security team never sees them. If your account contacts are a shared engineering mailbox, the fastest human signal may never reach the security team.

What the quarantine policy denies, version by version

AWSCompromisedKeyQuarantine is an AWS managed policy made entirely of Deny statements. Under IAM policy evaluation, an explicit deny overrides any allow, so AWS can switch off specific actions without touching the user's existing permissions. AWS has made two kinds of change over the years: minor versions that edit the policy in place, and major versions with a new name (V2, V3). Unit 42 reports that once a new version ships, AWS stops attaching the older ones.

The counts below come from pk-sharma.com parsing the JSON policy documents on AWS's reference pages for V1, V2 and V3, cross-checked against Unit 42's change tables.

AWSCompromisedKeyQuarantine versions. Dates from AWS policy reference pages and Unit 42 tables; action and service counts computed by pk-sharma.com from AWS's published JSON.

Policy and versionDate (UTC)Denied actionsWhat changed
AWSCompromisedKeyQuarantine v111 Aug 202028 in 5 servicesIAM, EC2, Organizations, Lambda, Lightsail
V2 v121 Apr 202155Adds 11 S3 actions plus 16 more IAM and Lambda actions
V2 v2 to v4Nov 2021 to Mar 202355 to 60Ownership-controls swap; cloudtrail:LookupEvents; Reserved Instance and Savings Plan purchases
V2 v52 Oct 202489 in 19 servicesBedrock, SageMaker, ECS, ECR, SES, STS tokens, Amplify, CodeBuild, Glue
V3 v1 and v221 Aug 2024; 2 Oct 2024Same as V2 v4, then V2 v5V3 v2 created 10 min 48 s after V2 v5
V3 v3 (current default)16 Mar 202699 in 21 services, plus 1 conditionalKMS, logs:PutLogEvents, Organizations exit, s3:PutEncryptionConfiguration

Unit 42's arithmetic holds: V2 added 61 actions to V1's 28, making 89, and those additions touched 17 services. Its V3 table stops at v2. The AWS reference page for V3 shows a third version, "v3 (default)", edited on 16 March 2026. That is 87 days after Unit 42's test, so the test almost certainly attached V3 v2; Unit 42 does not name the minor version. It also means the article, although dated 21 September 2026, describes a policy that has since changed.

V3 v3 adds ten actions: kms:PutKeyPolicy, kms:RetireGrant, kms:RevokeGrant, kms:ScheduleKeyDeletion, kms:DeleteImportedKeyMaterial, logs:PutLogEvents, organizations:LeaveOrganization, organizations:AcceptHandshake and s3:PutEncryptionConfiguration, plus a second statement that denies kms:CreateGrant whenever the request is not made through an AWS service. AWS gives no reason for any of these changes. Our reading, which is inference: they close routes to extortion by encryption (re-keying buckets, locking or deleting KMS keys) and a route out of organisational guardrails (leaving the organisation, and with it its service control policies). Unit 42 makes the same kind of link for earlier versions: s3:DeleteObject after data-theft extortion, and the Bedrock actions after Permiso's research on attackers invoking models with stolen keys.

One more sign of lag: AWS's own knowledge-centre article on unauthorised activity still tells readers to check that AWSCompromisedKeyQuarantineV2 is attached. It does not mention V3. If your runbook or detection rule matches only one policy name, check it against all three.

A quarantine is a deny list, not a lockdown

"Quarantine" suggests something sealed off. What AWS actually does is narrower, and Unit 42 says so plainly: AWS "purposefully denies specific actions rather than completely disabling the compromised access key or user password". A stricter AWS managed policy exists, AWSDenyAll, which denies everything. AWS chose not to use it because it would break any legitimate workload that uses the same key. That is a reasonable trade for an automatic action taken without the customer's consent. It is still a trade, and the customer carries what is left over.

What the word suggests against what the policy does. Sources: AWS policy reference, AWS support case text shown by Unit 42, AWS IAM and STS documentation.

What 'quarantine' suggestsWhat actually happensStated or inferred
The key is switched offThe key stays valid; listed actions return access deniedStated (Unit 42, AWS email)
The attacker is locked outAnything not on the list still works if the user's policies allow itFollows from IAM evaluation
It follows the stolen credentialIt is attached to the IAM user, so it covers all that user's keys and passwordStated (AWS support case)
It covers everything the key can reachRole sessions assumed with the key carry the role's permissions, not the user'sInference from STS documentation
AWS cleans upAWS attaches a policy and opens a case; rotation, investigation and clean-up are yoursStated (AWS support case)
It ends when the risk endsIt stays until someone with iam:DetachUserPolicy removes itStated (AWS support case)

The role-session point is the one most likely to catch teams out. According to the STS AssumeRole reference, a role session's permissions come from the role's identity-based policy, intersected with any session policy. The quarantine policy is attached to the user, not to any role the user can assume. So if the leaked user is allowed to assume a role, the policy does not deny sts:AssumeRole, and the resulting session is not restricted by the user's quarantine. This is our inference from AWS's documented evaluation model; neither Unit 42 nor AWS tested or described it.

Sessions created with GetSessionToken behave differently. AWS documents that they have the same permissions as the IAM user and that permissions on temporary credentials are evaluated each time they are used, so the user's deny list reaches those sessions too. V2 v5 also added sts:GetSessionToken and sts:GetFederationToken to the deny list, so the key cannot mint new ones.

What an attacker can still do while quarantined

The table below checks named actions against the JSON of the current V3 policy (v3, edited 16 March 2026). An action marked "Not listed" is not blocked by the quarantine. The attacker can use it only if the user's own policies already allow it. For a narrowly scoped deployment key that may be almost nothing. For an old administrator key, it is a lot.

Selected actions checked against the AWSCompromisedKeyQuarantineV3 v3 JSON policy, accessed 21 September 2026. Checked by pk-sharma.com.

ActionOn the V3 deny list?Why it matters
sts:AssumeRoleNot listedPivot into a role whose session the quarantine does not touch
secretsmanager:GetSecretValue, ssm:GetParameterNot listedRead stored secrets and parameters
ssm:SendCommand, ssm:StartSessionNot listedRun commands on instances already running
s3:GetObjectDeniedBlocks plain object reads
s3:GetObjectVersion, s3:ListBucketVersionsNot listedOlder object versions stay readable where versioning is on
s3:PutObjectNot listedOverwrite objects in place
ses:GetSendQuota, ses:ListIdentitiesDeniedBlocks SES reconnaissance
ses:SendEmailNot listedSend mail from verified identities
cloudtrail:LookupEventsDeniedThe attacker cannot read your event history
cloudtrail:StopLogging, cloudtrail:DeleteTrailNot listedTurn off your trail
iam:CreateAccessKey, iam:CreateUser, iam:CreateRoleDeniedBlocks the classic persistence moves
iam:DeleteUser, iam:DeleteLoginProfile, iam:DeactivateMFADeviceNot listedDestructive or disruptive identity changes
ec2:CreateSnapshot, ec2:ModifySnapshotAttributeNot listedCopy disks and share snapshots out
lambda:InvokeFunction, lambda:UpdateFunctionConfigurationNot listedRun or reconfigure existing functions

Two timing gaps sit either side of the quarantine. Before it: for 10 seconds in Unit 42's test, the key carried the user's full permissions. Anything done in that window, including creating a new key or user, is not undone by the quarantine. After it: the key stays valid with a partial deny list until a person acts. The Health event's 14-day end time is not an expiry for the key. Neither source says how long the key stays live.

The quarantine also restricts defenders. It denies iam:UpdateAccessKey, iam:DeleteAccessKey and iam:CreateAccessKey to the quarantined user, so the key cannot rotate itself. Rotation has to come from another identity with IAM rights. And cloudtrail:LookupEvents is denied, so any tooling that ran under that user will lose sight of event history.

What the customer still has to do

AWS's support case, shown in full in Unit 42's Figure 8, gives five steps. In summary: (1) replace the key: create a second key, move the application to it, make the exposed key inactive, then delete it; (2) check CloudTrail for unapproved IAM users, login profiles, access keys, policies, roles or temporary credentials, and delete them; (3) check for unwanted usage such as EC2 instances, Lambda functions or Spot bids in every Region, and review the bill; (4) detach the Quarantine Policy from the user; (5) reply to the case to confirm steps 1 to 3, "to restore access to your account, prevent suspension, and apply for a billing adjustment, if applicable". The case adds that rotating and deleting the key alone "may not be sufficient". AWS says it will consider billing adjustments only after the account is secured.

That list is sound but incomplete for a security team. Default CloudTrail event history covers 90 days of management events and does not show data events. Data events are not logged by default, and they include S3 object-level calls such as GetObject. If the leaked key read objects in its first 10 seconds, or read older object versions afterwards, you will not see it unless you already had data-event logging on. AWS's knowledge-centre article also points to revoking role sessions where temporary credentials are involved. IAM's revoke-sessions feature attaches an AWSRevokeOlderSessions deny to the role, covering sessions issued before the revocation time.

Remediation: what AWS's case asks for, set against what it leaves unstated. Sources: AWS support case text (Unit 42 Figure 8), AWS knowledge centre, IAM and CloudTrail documentation.

TaskIn AWS's support caseNot stated in the case
Rotate the keyYes: create, switch, disable, deleteThat the quarantined user cannot rotate its own key
Hunt persistenceYes: users, login profiles, keys, policies, roles, temporary credentialsTrust policy edits, new policy versions, federation tokens, instance profiles
Check usageYes: EC2, Lambda, Spot, every Region, billingBedrock, SES, SageMaker, ECS, which later versions target
Role sessionsNoRevoke sessions for roles the user could assume
Data accessNoS3 reads are data events and absent from default history
Remove quarantineYes, after steps 1 to 3Who in your organisation holds iam:DetachUserPolicy

Detecting a quarantine in your own logs

Do not rely on the email. Unit 42 suggests alerting on the CloudTrail event itself, and on GitHub's validity checks, which call sts:GetCallerIdentity with the leaked key from GitHub's network under a distinctive user agent. The user agent string contains GHAS-AWS_KEYID-validation; GitHub changed the rest of the string in early October 2025, so match on that fragment rather than the whole thing. Unit 42's indicator list gives both full forms.

Useful signals:

  • CloudTrail: eventSource = iam.amazonaws.com, eventName = AttachUserPolicy, and requestParameters.policyArn containing AWSCompromisedKeyQuarantine. Match the prefix so V1, V2 and V3 all fire.
  • AWS Health: the "Risk IAM quarantine" event. AWS documents that global events, including IAM, reach EventBridge only through a rule in US East (N. Virginia). We could not confirm the exact Health event type code for this alert, so match on the Risk service and test with your own rule.
  • Standing audit: list which users carry any quarantine policy today. A forgotten attachment is an unfinished incident.
# Which IAM users currently carry an AWS quarantine policy?
for p in AWSCompromisedKeyQuarantine AWSCompromisedKeyQuarantineV2 AWSCompromisedKeyQuarantineV3; do
  echo "== $p"
  aws iam list-entities-for-policy --policy-arn arn:aws:iam::aws:policy/$p --entity-filter User
done

# Recent quarantine attachments in the last 90 days of management events (IAM events log in us-east-1)
aws cloudtrail lookup-events --region us-east-1 \
  --lookup-attributes AttributeKey=EventName,AttributeValue=AttachUserPolicy \
  --max-results 50 --output json | grep -o 'AWSCompromisedKeyQuarantine[A-Za-z0-9]*' | sort | uniq -c

GitHub's push protection is not a complete net either. GitHub's own troubleshooting page says push protection skips pushes to public repositories larger than 50 MB and shows at most five secrets at a time, and that very large pushes may time out without blocking. Unit 42 flags the same limits.

Method, interest and what the research does not show

Unit 42 is the threat research arm of Palo Alto Networks. The article ends by promoting Cortex Cloud, Idira privileged access management and Unit 42's assessment and incident response services. That does not undermine the test: the timeline is supported by screenshots of CloudTrail, the Health dashboard, the email and the support case. But note its limits. It is one controlled exposure, of a user whose only attached policy, in Unit 42's Figure 3, was the quarantine policy itself. It measures AWS's reaction, not an attacker's. It does not test keys leaked in private repositories, container images, CI logs or paste sites, and it does not cover the V3 v3 changes.

There are also small inconsistencies worth knowing about. The alt text for the Health dashboard screenshot says the event started in 2018; the screenshot shows 19 December 2025. The text calls the attach event unattributed to AWS; the screenshot shows "AWS Internal" markers. And the article calls EC2 "Elastic Cloud Compute". None of these changes the findings. They are a reminder to check the figures, not just the prose.

AWS deserves credit. An automatic, provider-side deny list that goes on within seconds, without breaking legitimate workloads, is a real safeguard. AWS has kept extending it as attacker behaviour shifted, from crypto-mining to S3 deletion, generative AI abuse and, now, KMS. The point is not that the quarantine is weak. The point is that it was built to stop fraudulent spend, and a team that reads "quarantined" as "contained" will stop investigating too early.

What to do, in order

Take this with you

Actions for AWS account owners

  • Run list-entities-for-policy for all three quarantine policy names today, and treat any user still carrying one as an open incident.
  • Create a CloudTrail or EventBridge alert on AttachUserPolicy where the policy ARN contains AWSCompromisedKeyQuarantine, routed to the security team, not only to engineering.
  • Add an AWS Health EventBridge rule in us-east-1 for the Risk service, and check where your account's security contact emails actually land.
  • Write the quarantine runbook now: rotate the key from an admin identity, hunt persistence in CloudTrail across every Region, then revoke sessions for every role the user could assume.
  • Check whether each IAM user with long-term keys can call sts:AssumeRole, and into what; that is the part of the blast radius the quarantine does not cover.
  • Turn on S3 data-event logging for buckets holding sensitive data, so a future leak's reads are visible.
  • Update runbooks and detections that name only AWSCompromisedKeyQuarantineV2, as AWS's own knowledge-centre article still does.
  • Replace long-term IAM user access keys with role-based, short-lived credentials wherever you can; the quarantine exists because those keys leak.

The question to ask

AWS will very likely catch a key pushed to public GitHub within seconds, and it will tell someone. The questions it cannot answer for you are these: if AWS quarantined one of your keys tonight, who would see it first, and which roles could that key still assume after the quarantine went on?

Key facts

Sources

  1. PrimaryFrom Exposure to Lockdown: primary research; exposure test timeline, screenshots of CloudTrail, Health, email and support case, policy version tables, GitHub user agentsUnit 42, Palo Alto Networksaccessed 2026-09-21
  2. PrimaryAWSCompromisedKeyQuarantineV3 managed policy reference: description, creation and edit dates, current v3 JSON used for action counts and absence checksAWSaccessed 2026-09-21
  3. PrimaryAWSCompromisedKeyQuarantineV2 managed policy reference: v5 JSON, dates, descriptionAWSaccessed 2026-09-21
  4. PrimaryAWSCompromisedKeyQuarantine (V1) managed policy reference: original 28-action JSONAWSaccessed 2026-09-21
  5. PrimaryWhat to do about unauthorised activity: remediation steps, still references V2AWS re:Post Knowledge Centeraccessed 2026-09-21
  6. PrimarySTS AssumeRole API reference: role session permissions come from the role's policiesAWSaccessed 2026-09-21
  7. PrimaryIAM guide: GetSessionToken credentials have the same permissions as the IAM userAWSaccessed 2026-09-21
  8. PrimaryIAM guide: permissions on temporary credentials are evaluated on each requestAWSaccessed 2026-09-21
  9. PrimaryIAM guide: revoking role sessions with AWSRevokeOlderSessionsAWSaccessed 2026-09-21
  10. PrimaryIAM policy evaluation logic: explicit deny overrides allowAWSaccessed 2026-09-21
  11. PrimaryCloudTrail event history: 90 days of management events, no data eventsAWSaccessed 2026-09-21
  12. PrimaryCloudTrail data events: not logged by default, include S3 GetObjectAWSaccessed 2026-09-21
  13. PrimaryAWS Health EventBridge rules: global events including IAM need a US East (N. Virginia) ruleAWSaccessed 2026-09-21
  14. PrimarySecret scanning partner programme: public repositories and npm packages, alerts to partnersGitHubaccessed 2026-09-21
  15. PrimaryPush protection limits: 50 MB public push skip, five secrets shown, large-push timeoutsGitHubaccessed 2026-09-21

Share this briefing

Know someone who owns this problem? Send it to them.

Related briefings

The briefing, in your inbox

Practitioner analysis of cyber and AI security news. No vendor noise.

One email per briefing. Unsubscribe any time.