Sitemap

How an AWS Attack Works, From Leaked Key to Data Theft

5 min readSep 24, 2026

--

Press enter or click to view image in full size
Five linked stages of a cloud intrusion running from a leaked key to stolen data
Only the first move is an exploit. The other four are IAM as written.

The route from a leaked key to stolen data, and the one permission decision that sets the blast radius.

An AWS attack is mostly identity, and only the opening move is a real exploit.

Datadog puts IMDSv2 enforcement at 66% of EC2 instances, up from 47% a year earlier. The remaining third answer any caller that asks, and they are the oldest machines in the estate.

Table of Contents

  1. The Three Doors Into an AWS Account
  2. Why the Metadata Service Answers Any Caller
  3. The Reconnaissance Nobody Alerts On
  4. Why Temporary Credentials Never Stopped an AWS Attack
  5. Where the Chain Actually Breaks

The Three Doors Into an AWS Account

Most intrusions in AWS do not start with an attack on AWS. Three doors carry almost all of them: a long-lived access key sitting in a repository or a ticket, a build pipeline holding deployment credentials, and a web service with a server-side request forgery flaw. Datadog’s 2025 cloud security study calls the first kind static credentials that never change and never expire.

Datadog’s current figures put 59% of AWS IAM users on an access key older than a year, so door one is not a rare accident. Here is the example this piece follows to the end: a public product service on EC2 offers an image preview, you paste a link, the server fetches it. An ordinary feature, about to become a question about identity.

Why the Metadata Service Answers Any Caller

Every EC2 instance can reach a link-local address, 169.254.169.254, that exists only from inside it. The instance metadata service listens there and returns temporary credentials for the attached IAM role, and it cannot tell an application apart from a flaw in that application. The AWS instance metadata guide sets out the version 2 handshake:

TOKEN=$(curl -sX PUT 169.254.169.254/latest/api/token \
-H "X-aws-ec2-metadata-token-ttl-seconds: 60")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
169.254.169.254/latest/meta-data/iam/security-credentials/

A plain address fetch cannot set a header, so the request forgery path dies at the door. Datadog’s 2025 state of cloud security report puts enforcement at 66% of instances, up from 47% a year earlier. The oldest third of the fleet still answers the old way.

Press enter or click to view image in full size
A web server fetching the instance metadata address and handing back temporary role credentials
The preview feature asks for a link. The metadata service answers with keys.

The Reconnaissance Nobody Alerts On

An attacker now holds credentials for a role and no idea what the role can do, so they ask the account. Every call in the enumeration that follows is a read, and reads are the calls nobody writes a detection for:

aws sts get-caller-identity
aws s3api list-buckets
aws lambda list-functions
aws secretsmanager list-secrets
aws iam get-role --role-name preview-service

Nothing there looks like an attack, and CloudTrail records every call as a normal working day. The SCARLETEEL cloud intrusion is the documented version, where a compromised container led to the metadata service, then to enumerated Lambda functions whose source code left the account. What decided that outcome was the policy attached to one workload role, written whenever the stack was first deployed.

Why Temporary Credentials Never Stopped an AWS Attack

The usual comfort is that metadata credentials expire in a few hours. They do, and the attacker fetches a fresh set through the same flaw, or converts one short session into a new IAM user with its own access key. Persistence is created with the access, not stolen alongside it.

Get Cloud Under Fire’s stories in your inbox

Join Medium for free to get updates from this writer.

The role running a web server rarely holds the data anyone wants, so the hunt is for a path to a role that does. Four permissions carry most of that traffic, and the AWS PassRole documentation is explicit about the first:

  • iam:PassRole, hand a more privileged role to a resource you can launch
  • iam:AttachRolePolicy, widen a role you already control
  • secretsmanager:GetSecretValue, read the credential that opens the next system
  • lambda:UpdateFunctionCode, change code that already runs as something stronger
{
"Effect": "Allow",
"Action": ["iam:PassRole", "lambda:UpdateFunctionCode"],
"Resource": "*"
}

Where the Chain Actually Breaks

The control does not go at move one. You will not prevent every leaked key and every request forgery flaw, and a defense that assumes you will is a hope with a budget line. The chain breaks at move three, and the cheapest cut there is one command:

aws ec2 modify-instance-metadata-options --instance-id "$ID" \
--http-tokens required --http-put-response-hop-limit 1

Back to the image preview. With version 2 required the fetch returns nothing, and with the role scoped to the two buckets the service names, even a successful theft returns two buckets. Tooling such as Rival Security’s agent harness sorts reachable exposure from noise, though deciding what to cut stays a human job.

  1. Pick your three most internet-exposed workload roles.
  2. Generate a replacement policy from recent CloudTrail activity with IAM Access Analyzer, then diff it against what is granted.
  3. Scope each role to the resources it names, with no account-wide reads.
  4. Retire every access key older than a year and hand the job to a role.

AWS Attack FAQs

Does an AWS attack need a zero day?

No. The common route is a credential that already exists, reached through a leaked key, a build pipeline, or a request forgery flaw in an ordinary feature. The exploit, where there is one, only reaches the identity layer.

Does IMDSv2 stop credential theft on its own?

It closes the plain fetch of the metadata address, which is the path most request forgery flaws take. It does nothing about a leaked key or a pipeline token, so the role policy still decides how far anyone gets.

Why do read-only API calls go unnoticed?

Reads succeed, so they leave no failed login and no denied action to alert on. CloudTrail records them, yet almost nobody writes a detection for an identity reading its own permissions.

What should a workload role be allowed to do?

Only the actions it has actually called, against the resources it names. Generating a policy from recent CloudTrail activity turns that scope from an argument into a diff you can review and apply.

This article expands on our video “How does an AWS attack work, from first access to data theft?”. Watch it here.

--

--