tl;dr AWS applies a quarantine policy to leaked keys without disabling them. Our research found critical gaps that leave existing permissions to read secrets, run server commands, and delete databases or backups in place. In the wild, we found 894 exposed keys with quarantine attached and grants for dangerous actions outside its deny list.
An AWS key ends up in a public GitHub repo. AWS can respond by attaching a quarantine policy to the IAM user that owns it. The policy is a list of actions the user is forbidden to perform. It leaves the key active.
Launching a new EC2 instance is on that list. Retrieving a secret or deleting a database is not. If the user already has permission for those actions, quarantine leaves those grants in place.

What the policy does, illustrated. The uncovered operation still needs an applicable grant and must pass other account and resource controls.
The quarantine policy has changed over the years but it still has gaps
AWS has introduced three separate quarantine policies over the years: the original in 2020, V2 in 2021, and V3 in 2024. Attaching the original policy does not give a user V2 or V3’s restrictions. In our dataset, 738 keys had an older policy listed without V3.
V2 and V3 have also received updates under the same names. The original is still unchanged from 2020. A key with only that policy misses restrictions added in the newer ones.

Restrictions that differ across the three policies. The original appeared on 112 keys, V2 on 628, and V3 on 191; two keys listed both original and V2.

Gaps shared by all three policies. “Not denied” means quarantine leaves the action uncovered; an existing grant and other access controls still determine whether it succeeds.
Those restrictions matter. Among the keys with matching grants, quarantine removes ordinary S3 reads from 788 and Lambda code updates from 728.
The full definitions: original, V2, V3.
We investigated 929 quarantined keys
To see whether these gaps appeared in the wild, we revisited our August study of leaked credentials. We found 929 keys that still authenticated and had quarantine listed on their IAM users, across 909 accounts. They had been exposed in code, datasets, images, and other public sources.
The keys could still list the policy names attached to their own IAM users. We matched those names to AWS’s public policy definitions to see what access quarantine left in place. On 894 keys, those policies contained grants for dangerous actions that quarantine did not deny.
These credentials had often been around for years. Creation dates were available for 926 keys. Their median age was 3.6 years, the oldest was 12.3 years, and 231 were at least five years old.
Quarantine had not led to revocation for these keys. More than a hundred keys still authenticated over three years after we first recorded their exposure. The age breakdown is below.

Key age from IAM creation dates, measured at the August 10, 2026 authentication snapshot. This measures how old the credentials were, not how long they had been exposed or quarantined. Three creation dates were unavailable.
The S3 read block still leaves a download path
V2 and V3 deny s3:GetObject, the permission for an ordinary S3 download. They do not deny s3:GetObjectVersion. A key that still has that permission can download a specific version of the object, including the current version when its version ID is supplied.
The response contains the file’s contents. Supplying a version ID changes which permission AWS checks. AWS’s GetObject documentation explicitly says that s3:GetObject is not required for that request.

Illustrative requests for the same object, not a download test. The version-specific route still needs an existing version-read grant and must pass other access controls.
The download still needs an accessible object version and must pass bucket policies, encryption permissions, and other controls. But quarantine’s ordinary S3 read block does not close this route to the data.
Which permissions can lead to more access?
Some gaps let an attacker move beyond the leaked user’s access. Others let them take data directly. We found at least one dangerous grant outside quarantine’s deny lists on 894 of the 929 keys.
Assume a role.sts:AssumeRole can return credentials for another role. If a suitable role trusts the user, the attacker can use that role’s permissions. The user’s quarantine policy does not automatically carry over to the new session. We found matching grants on 801 keys; we did not establish which roles they could reach. See AWS’s role-session guidance.
Run commands on an existing server.ssm:SendCommand and ssm:StartSession can provide command execution or a shell on a configured managed node. Depending on the command or session’s operating-system privileges, that access can expose credentials and permissions available to the machine. Quarantine leaves both actions uncovered. See AWS’s Run Command and Session Manager documentation.

Matching grants left uncovered. Role trust, server configuration, policy scope, and other controls determine whether a path is usable. Counts overlap.
Change a policy. The original quarantine policy also leaves iam:CreatePolicyVersion and iam:SetDefaultPolicyVersion uncovered. With permission over an attached customer-managed policy, those actions can make a more permissive version take effect. V2 and V3 close these gaps.
Which permissions allow data theft?
The gaps reach beyond S3 and stored secrets. Quarantine also leaves table reads, snapshot sharing, cache exports, logs, and deployment-code downloads outside its deny lists. The table shows the matching grants we found in the same 929-key dataset.

Counts match saved policy names to public AWS definitions unchanged since the August snapshot. We did not test these operations; custom policies and additional controls can change effective access. Counts overlap.
DynamoDB scans return table items. RDS snapshot sharing and EBS snapshot sharing can make stored data available to another account, subject to snapshot and encryption restrictions. Lambda GetFunction can return a download link for the deployment package.
AWS documents backup exports for serverless Memcached, Redis, and Valkey, but not node-based Memcached. Exports need suitable snapshots and an S3 destination with the required permissions. Redshift credentials still need a reachable database and a database user with access to the data.
Encrypted data may also require kms:Decrypt. Quarantine leaves that action uncovered too, although the KMS key policy and other controls still apply. Credentials taken from secrets or servers can then become access to another system.
Why block EC2 launches but allow EC2 command execution and termination?
AWS says V3 aims to limit fraud-related charges while avoiding disruption to existing resources. Cryptomining is a plausible reason to focus on compute launches: AWS has documented attackers using compromised credentials to launch EC2 and ECS mining workloads.
Our inference is that the launch/terminate split reflects that spending focus. Launching or starting compute can add mining capacity and charges; terminating an instance removes that capacity. The policy documentation does not explain that specific omission. Leaving termination uncovered can still give an attacker a way to disrupt an existing service.
Revocation has to catch up
In the Hugging Face breach, AI agents recovered 14 publicly exposed credentials with write access, then used that access to chain exploits into Hugging Face’s systems. The incident report shows how exposed credentials became a starting point for a much larger compromise.
Across providers, Truffle is aware of more than a million live, exposed credentials. We are not ready for attacks at AI speed while that access remains available. Meaningful progress means revoking exposed credentials at scale. We are working toward solutions that help close that gap.


