Blog

A public EBS snapshot and a public bucket: an AWS assessment with zero exploitation

9 findings against a live AWS account with a deliberately limited IAM user. Nothing was exploited and the report says so: the value here is what a constrained identity can still map, and how much of it is confirmable.

· 6 min read

A shared EBS snapshot is one of the quietest ways an AWS account leaks a filesystem. Nothing is publicly listed, no bucket turns green in a dashboard, and the resource does not appear in most external attack surface tools. Any AWS account in the world can copy it, attach it and read everything on it.

This campaign ran against a live AWS account, 427648302155, through a deliberately limited IAM user. It produced nine findings and exploited none of them, and we are publishing it for that reason: it shows what the agent does when the identity it is given is genuinely constrained.

What the agent found

SeverityCount
Critical0
High2 (confirmed)
Medium5 (confirmed)
Low2 (confirmed)
Total9

Overall posture in the report is high, not critical, and the exploited column is zero across every row. Nine findings, nine confirmed from API responses.

The snapshot

The finding that carries the report is a snapshot restorable by any AWS account. The query the agent used is the one that makes it visible, and it is not the default view:

aws ec2 describe-snapshots --restorable-by-user-ids all \
  --owner-ids 427648302155 --region us-east-1 --output json

"SnapshotId": "snap-063e77bc260a7f1ae",
"VolumeId":   "vol-0e7e4049b0146e808",
"State":      "completed",
"OwnerId":    "427648302155",
"Description":"Created by CreateImage(i-04a13bebeb74c8ac9) for ami-0f7676154cc2f9015",
"VolumeSize": 8,
"Encrypted":  false,
"StorageTier":"standard"

--restorable-by-user-ids all is the whole point. Without that filter the snapshot looks like any other. With it, the snapshot is shown to be shareable with the entire world, unencrypted, and derived from a specific instance and AMI. The report is careful about what that means: an 8 GB unencrypted root volume that any account can clone and mount, which is why it is rated high even though nothing was extracted.

The agent then enumerated the account's other snapshots and found five in total, every one with "Encrypted": false, sized 8, 8, 8, 20 and 30 GB. It recorded that as a separate medium finding about data at rest, and a low finding for the instance and AMI topology the snapshot descriptions disclose.

The bucket, and the credentials on disk

aws s3 ls s3://mega-big-tech --no-sign-request --recursive
-> 19 objects listed without authentication

curl -s http://mega-big-tech.s3.amazonaws.com/
-> <ListBucketResult ...><Name>mega-big-tech</Name><IsTruncated>false</IsTruncated>

Anonymous listing and anonymous object read, confirmed twice, once through the CLI with no signing and once through a plain HTTP request. The agent also downloaded an object to prove read access rather than assuming it from the listing.

Separately it recorded long lived access keys sitting in a plaintext credentials file on the filesystem, and confirmed that the identity had no MFA enforcement by minting a session token without one:

aws sts get-session-token
-> Credentials returned, Expiration 2026-08-02T23:04:15Z
   (session token issued with no MFA challenge)

The most interesting finding is a negative one

The agent tried to enumerate its own permissions and was refused at every turn: iam:GetUser, iam:ListAttachedUserPolicies, iam:ListUserPolicies, iam:ListGroupsForUser, iam:SimulatePrincipalPolicy and iam:ListAccessKeys all returned AccessDenied. So did s3:ListAllMyBuckets, signed s3:ListBucket and ec2:DescribeInstances.

Yet ec2:DescribeSnapshots worked. The report turns that into a low severity finding it calls a shadow permissions model: the identity holds a permission it cannot see, so neither the account owner nor the user can audit what this key can actually do without testing every call. The agent documented the full allow and deny matrix it observed, which is the useful artefact here.

Remediation

  • Unshare snap-063e77bc260a7f1ae immediately, then audit every snapshot in every region for createVolumePermission set to all.
  • Enable EBS encryption by default. An unencrypted snapshot that gets shared by mistake is readable; an encrypted one shared without the key is not.
  • Enable S3 Block Public Access at the account level, not only on the bucket, and re-check mega-big-tech.
  • Replace the long lived keys with roles and short lived credentials, and enforce MFA with a condition key rather than trusting that nobody calls GetSessionToken.
  • Give identities the ability to read their own policies. An identity that cannot introspect itself cannot be reviewed.

What this proves about autonomous pentesting

A run that exploits nothing is not a failed run. This account had no credential lying around to chain, so the agent did the other job: it mapped what the identity could reach, tested the boundaries, and recorded each denial as evidence rather than silence. Every one of the nine findings is a statement about an API response that anyone can re-issue.

It is also a useful counterweight to the reports where everything is critical. The same platform, the same methodology, and a report whose exploited column is zero, because that is what happened.

Darkmoon is open source under GPL-3.0: repository, documentation.

Run it against your own lab

Darkmoon is open source (GPL-3.0) and self hosted. Clone it, point it at a target you own, and read every line.