All IAM escalation methodsCritical severity
AWS IAM privilege escalation • ec2:ModifyInstanceAttribute

ec2:ModifyInstanceAttribute User Data Privilege Escalation

ec2:ModifyInstanceAttribute lets a principal rewrite the user-data script of an existing EC2 instance. If that instance already carries a privileged instance profile, the attacker injects a script that runs as root on next boot and exfiltrates the role's credentials — no iam:PassRole needed at all.

Permissions an attacker needs

  • ec2:ModifyInstanceAttribute
  • ec2:StopInstances
  • ec2:StartInstances

How the escalation works

  • The attacker finds a running instance already attached to a privileged instance profile — they never need permission to launch instances or pass roles, only to modify one that already exists.
  • They stop the instance, then call ModifyInstanceAttribute to overwrite its user-data with a payload using the #cloud-boothook directive (or a cloud-config "scripts-user: always" module), which forces execution on every boot instead of only the first.
  • They start the instance. The payload runs as root, reads the instance role's temporary credentials from the instance metadata service, and exfiltrates them for use anywhere.

Example vulnerable policy

A policy like this grants the dangerous permission. Paste your own policy into the free AI-Powered IAM analyzer to see if you are exposed.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:ModifyInstanceAttribute",
        "ec2:StopInstances",
        "ec2:StartInstances"
      ],
      "Resource": "*"
    }
  ]
}

Example exploitation

For illustration only — run against accounts you own or are authorized to test.

aws ec2 stop-instances --instance-ids i-0abc123
aws ec2 modify-instance-attribute \
  --instance-id i-0abc123 \
  --attribute userData \
  --value file://payload-boothook.b64
aws ec2 start-instances --instance-ids i-0abc123
# payload-boothook.b64 decodes to a #cloud-boothook script that curls
# http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>
# and exfiltrates the temporary credentials on every boot.

How to detect and prevent it

  • Restrict ec2:ModifyInstanceAttribute (and the stop/start pair needed to trigger it) to administrators, separate from general EC2 operating permissions.
  • Least-privilege the instance role itself, since anyone who can reach it via this path gets its full permission set.
  • Enforce IMDSv2 — it does not block this technique (the payload runs on the instance and can complete the token handshake locally) but it does close the separate remote-SSRF credential-theft path.
  • Alert on ModifyInstanceAttribute (userData) calls in CloudTrail, especially immediately after StopInstances and before StartInstances on the same instance.

FAQ

Why is this different from PassRole + RunInstances?

RunInstances requires iam:PassRole and launches a brand-new instance. This method needs no IAM permission at all — it targets an existing instance that is already attached to a privileged profile, only rewriting its user data.

Why can't the attacker just modify user data on a running instance?

AWS only accepts ModifyInstanceAttribute for userData while the instance is stopped, and by default cloud-init only executes user data once, on first boot — the stop/start cycle plus the #cloud-boothook directive are both necessary to force re-execution.

Related escalation methods

Check your IAM policies for this — free

Shieldly's AI-Powered analyzer flags privilege-escalation paths, wildcards, and risky PassRole in seconds. No signup, no AWS credentials. Also ships as CLI, VS Code extension, GitHub Action, and CDK Guard.

Amazon Web Services (AWS) is a trademark of Amazon.com, Inc. Shieldly is not affiliated with, endorsed by, or sponsored by Amazon Web Services.