
The AWS Puzzle: Can a simple curl really compromise an entire AWS account? (Part 1: The Attack)
AWS is like a jigsaw puzzle: each service seems harmless on its own, but leave a few loose pieces and they snap together to form a critical breach. In this first post, I share what I uncovered in my hands-on lab: how everyday oversights in S3, a lightweight web app, and the metadata service align against a single curl command, proving that mastering cloud fundamentals matters far more than relying on complex hacking tools.
Series: The AWS Oversights Puzzle (Level 100: Fundamentals) (2 articles)
- 1The AWS Puzzle: Can a simple curl really compromise an entire AWS account? (Part 1: The Attack) This article
This article is an English edition of my original post published on AWS Builder Center (read in Spanish ). While the live demonstration video and terminal screenshots were recorded during a live community talk in Mexico, all step-by-step commands, CloudFormation templates, and repository instructions are universal so you can deploy and audit every single attack vector in your own AWS account.
Can a simple command really break cloud security?
A few weeks ago, the AWS User Group Minatitlán invited me to deliver a talk on cloud security. In tech meetups, we often hear the same defensive theory over and over: "close this port", "don't open this bucket", "follow the best practices".
But I wanted to break that routine, stand on the other side of the fence, and answer a very simple question:
How far into an AWS account can someone get if they only know basic AWS Cloud Practitioner concepts and start running simple terminal commands?
The premise of this experiment was very clear: zero complex hacking tools and zero Hollywood-style exploits. I wanted to prove whether relying solely on foundational AWS Cloud Practitioner building blocks (Amazon S3, Amazon EC2, IAM, and the instance metadata service) alongside basic requests with
curl could compromise a real cloud account when everyday misconfigurations align.Because in the cloud, the problem rarely arrives through a sophisticated attack: it happens when a puzzle of small everyday oversights snaps together.
Part 1 of 3: During our live stream, we walked through the entire lab end-to-end, but writing everything in a single post would have resulted in an excessively long article. That is why I decided to structure it into a 3-part series: today we start with the attacker's perspective (Red Team), we will follow up with defensive operations and auditing (Blue Team), and finally wrap up with web application security.
The Deployment: Everything in a Real, Isolated Account
For this experiment to be 100% authentic—rather than an artificial synthetic simulator where metadata behavior and IAM policy propagation are often lost—the lab was executed in a real AWS environment.
But here comes the first practical governance and security lesson: how do you present a live lab on screen without exposing client workloads or production accounts?
Instead of using standalone loose accounts or risking mixed environments, I leveraged the structure of my AWS Organization: I provisioned a dedicated, fully isolated member account (Workshops / Sandbox). Through AWS IAM Identity Center (AWS SSO) with mandatory MFA, I configured an exclusive user with access strictly scoped to that workshop account through the
LabRedTeamAccess role.This way, during the live stream, nobody in the audience could see the other accounts in the organization, containing the blast radius to 100% and keeping costs to a bare minimum by running on a single modest
t2.micro instance:
Environment isolation: secure sign-in with MFA and temporary role dedicated exclusively to the workshop.
Why Didn't We Use Infrastructure as Code?
During the session, I shared a deliberate design decision: I did not use external tools like Terraform.
The reason? Practicality and accessibility. If someone is taking their first steps in AWS or studying for the AWS Cloud Practitioner, requiring them to install third-party tools or configure remote state adds an unnecessary barrier that distracts from the central objective: understanding cloud architecture and security.
That is why I decided to package the entire lab into an interactive Bash assistant (
./redteam). Anyone who clones the project only needs to run the script and select option 1. Behind the scenes, the script natively calls AWS CloudFormation (infra/cloudformation.yaml), provisioning the VPC, public subnet, vulnerable S3 bucket, and EC2 instance in less than 3 minutes:
Deployment in 3 minutes: native declarative infrastructure executed through the redteam assistant.
Here is where our journey begins. Let's analyze how the puzzle came together piece by piece.
Piece 1: The False Security of Amazon S3 ("If they can't list, nothing happens")
Some organizations make the mistake of leaving configurations exposed due to bad practices, such as keeping Block Public Access disabled in S3 or using overly permissive policies that allow listing and downloading files (
s3:GetObject). This leaves sensitive information exposed within reach of anyone on the internet, such as fiscal tax invoices or .sql database backups.How does an outsider stumble upon this?
Most of the time, this is not a targeted attack or an organized group. It can simply be someone curious spending a quiet afternoon testing basic Google searches (Google Dorking) to see what files were indexed publicly:
1
2
3
site:s3.amazonaws.com "factura" ext:xml
site:s3.amazonaws.com "backup" ext:sql
site:s3.amazonaws.com "RFC" ext:pdfOr someone out of pure curiosity running a tool like
s3scanner with a list of common words (wordlist_s3_mexico.txt) to discover existing bucket names.If that person attempts to list the contents using the AWS CLI:
1
aws s3 ls s3://lab-red-team-public-data-xxxx --no-sign-requestAWS responds with an outright Access Denied. And this is where many administrators become complacent: "If nobody can list my folders, my data is secure."
The flaw: The policy had
s3:GetObject open. If someone knows or guesses typical file paths (/facturas/ or /backups/), a simple request with curl downloads the information immediately without asking for any credentials:1
2
curl -s https://<bucket-name>.s3.amazonaws.com/facturas/factura_sat_ejemplo.xml
curl -s https://<bucket-name>.s3.amazonaws.com/backups/backup_db_clientes.sql
When s3:GetObject is open, the inability to list directories does not prevent direct download when knowing the path.
For the live demonstration, I loaded representative examples of what typically leaks in real incidents: simulated tax invoices, a fictitious
.sql backup (never exposing real client data), and, as a gift to share with the community, the Official 2026 AWS Scholarships & Opportunities Guide featuring over 20 free initiatives.Simply knowing the object path is enough for a plain HTTP call to retrieve it. If the policy permits anonymous
s3:GetObject, the assumed privacy of the bucket is merely an illusion.Piece 2: The Unvalidated Web App (SSRF in Code)
On our EC2 server, we have a simple Python/Flask application (
app.py) to preview web links, where the function receives the user's parameter and performs a direct request without sanitizing the input:1
2
3
4
5
6
7
def preview():
target = request.args.get('url')
if target:
res = requests.get(target, timeout=3)
return res.text
return render_template('index.html')The developer thought: "The user will input http://google.com to test the connection."
But what happens if the user inputs an address from the internal network itself? That is Server-Side Request Forgery (SSRF): forcing the server to make HTTP requests on your behalf toward destinations you could never reach from the public Internet.
The story of the helpful waiter and the management badge:
To explain this concept to the audience simply, I presented this everyday situation:
Imagine you are a customer sitting at a table in a restaurant. From your table, you cannot enter the manager's office: the door is locked, and if you try to get in, security stops you immediately.
But who can enter that office freely? The waiter. He has an employee badge, and the door opens for him without questions.
Now imagine you call the waiter over and tell him: "Hey friend, go to the management office and bring me last year's tax reports and the access keys."
And the waiter, programmed to politely fulfill any request without validating who asks or why, simply says: "With pleasure." He walks into the internal office using his legitimate badge, takes the confidential documents, and quietly delivers them to your table.
In the cloud, the exact same thing happens: from your home on the Internet, you cannot send a direct request to the internal AWS metadata IP (
169.254.169.254). But you ask the vulnerable web server (the waiter) to go on your behalf. And the server, which has permissions assigned through its IAM Role (its badge), queries the internal metadata, extracts the account keys, and delivers the credentials straight to your browser screen.Piece 3: The Magic IP 169.254.169.254 and the Mixed Characters in the URL
In AWS, every EC2 virtual machine has a direct channel with its instance metadata service (IMDS) via the link-local IP address (RFC 3927)
169.254.169.254. This IP address does not exist on the Internet; it is reserved and only responds to requests sent directly from the server's own internal network interface.If the instance has IMDSv1 configured (which was historically enabled by default if not restricted upon creating the machine), any standard HTTP GET request pulls information from that IP without requiring passwords or tokens.
Why do we see characters like %3A%2F%2F in the request?
If you observe the address bar or console, the query travels with a peculiar combination:
http://<EC2-PUBLIC-IP>/?url=http%3A%2F%2F169.254.169.254%2Flatest%2Fmeta-data%2F...Why that mix? It is called URL-Encoding (Percent-Encoding):
%3Arepresents the colon (:).%2Frepresents the slash (/).
When an application receives a full URL as a parameter inside another URL (
?url=...), characters like :, /, or ? have structural functions in HTTP. If you send them unencoded, the receiving web server interprets the slashes as paths within its own site, and the request fails with a 400 Bad Request error. Encoding ensures that the entire internal address travels intact to the backend.From the browser to the terminal: "Can it really be that easy?"
Seeing the web interface, many will ask: "Can hacking a server really be that easy?". In the browser everything looks trivial because you only see a text box where you paste an address and press a button.
But in the terminal, the story requires understanding the protocol: handling quotes in Bash so the shell does not interpret the
? sign as a wildcard, sending the proper encoding, and parsing the plain text responses:1. Discover what IAM role is attached to the server:
1
curl -s "http://<EC2-PUBLIC-IP>/?url=http%3A%2F%2F169.254.169.254%2Flatest%2Fmeta-data%2Fiam%2Fsecurity-credentials%2F"The backend server processes the request and responds with the role name:
lab-red-team-ec2-role.2. Request temporary session credentials:
With the role name identified, the second request targets that endpoint:
1
curl -s "http://<EC2-PUBLIC-IP>/?url=http%3A%2F%2F169.254.169.254%2Flatest%2Fmeta-data%2Fiam%2Fsecurity-credentials%2Flab-red-team-ec2-role"The web server queries the link-local IP and returns the JSON document generated by AWS Security Token Service (STS):
AccessKeyId: Temporary key (ASIA...prefix).SecretAccessKey: Cryptographic signing secret key.Token: Ephemeral session token (~800 Base64 bytes).Expiration: UTC expiration date and time (typically 6 hours).

SSRF pivot: the web server queries internal metadata and leaks the associated role session keys.
Piece 4: The Role with Administrator Permissions (The Escalation)
Up to this point, the attacker only has temporary keys for a virtual machine. Why does this escalate into a catastrophe?
Because often, during development or the rush to deploy to production, the EC2 instance is assigned a role with broad permissions (
AdministratorAccess or policies with "Action": "*" and "Resource": "*"): "so the application doesn't trigger permission errors".The attacker exports those three variables on their local laptop:
1
2
3
export AWS_ACCESS_KEY_ID="ASIA..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_SESSION_TOKEN="..."And runs in their local terminal:
1
aws sts get-caller-identityIn that second, vertical privilege escalation took place: the attacker is no longer an anonymous user on a web page. They now hold the identity of a privileged role within the AWS account. They can list private buckets, inspect other instances, alter databases, or provision infrastructure:

Vertical privilege escalation: stolen credentials grant administrative access to private resources.
The Attack Puzzle
Looking at the full chain, not a single step required an alien exploit:
- An S3 bucket with Block Public Access disabled.
- An unvalidated field in a web app (SSRF).
- An instance with IMDSv1 active (
169.254.169.254). - An IAM role with administrator privileges.
AWS is like a large puzzle: each service (EC2, IAM, S3) is an independent piece. We can build resilient architectures combining them, but if we leave a piece loose—a role with
*, an open bucket, an unprotected metadata service—the entire structure becomes vulnerable.And the most revealing part: the syllabus concepts of the AWS Cloud Practitioner are enough to understand how an account gets compromised. No magic needed: just understanding how each component interacts.
Questions to Take Home
To close this first installment, here are the reflection questions I shared with the community:
- Did you know that with a simple
curland the magic IP169.254.169.254, temporary keys could be extracted from your server? - How many times have you seen Administrator permissions assigned to an EC2 role in development "so the app doesn't throw errors"?
- Have you identified which buckets in your account allow public access and whether someone could guess your backup paths?
Have you experienced or witnessed these types of oversights in your projects? I would love to read your perspective and stories in the comments.
And Now How Do We Defend This? (The Bridge to Part 2)
In Part 2 of this series, we will put on our Blue Team and Auditing hat:
- Why sanitizing the web app is not enough, and how to harden the infrastructure with IMDSv2.
- The production dilemma: why not all companies can enforce IMDSv2 immediately due to legacy SDKs, and how to manage that risk.
- Why port 22 (SSH) must be retired in favor of AWS Systems Manager (SSM).
- The CloudTrail trap: why your S3 downloads are not audited by default.
- How to deploy and tear down the entire lab for $0 USD.
The Challenges I Faced While Publishing This Article
To be honest: this post took me significantly more time than I anticipated.
The main reason was not building the code or provisioning the infrastructure in AWS, but rather that the automated moderation system on AWS Builder Center censored and invalidated almost all of the original screenshots I took.
Between Amazon Rekognition filters flagging terminal wallpaper background elements as inappropriate content, to automated rules blocking images for displaying literal key parameter names (
AccessKeyId, SecretAccessKey) or direct requests to the metadata IP, it was a genuine compliance and auditing journey over my own lab evidence.Still, that is part of documenting security topics publicly, I suppose..., since this is my first technical security article.
- Lab Repository: Siegfried-FS/lab-red-team
- Live Talk:
Live community workshop in Spanish hosted by AWS User Group Minatitlán
(Session anecdote: I thought the workshop would last an hour and a half, but during the transmission I suddenly saw a message in the chat that said: "You have 15 minutes left". Imagine the adrenaline rush! I had to accelerate and synthesize the conclusion right on the spot. The great thing about having built and tested the lab yourself is that you know exactly what is most critical to highlight in that remaining time).
#content-creators-latam #AWS #Security #Community #RedTeam
Series: The AWS Oversights Puzzle (Level 100: Fundamentals) (2 articles)
- 1The AWS Puzzle: Can a simple curl really compromise an entire AWS account? (Part 1: The Attack) This article
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article