Server-Side Request Forgery (SSRF) is one of those bugs that looks tiny on the surface but can blow a cloud workload wide open. Modern cloud platforms expose “metadata endpoints” to help instances discover their own configuration, and SSRF turns those internal helpers into attack surfaces.
Let’s break it down in a way that’s easy to follow and practical for everyday software development.
What is SSRF?
SSRF happens when an attacker can make your server send HTTP requests to targets they choose. If your backend fetches URLs based on user input - image previews, webhook validators, PDF converters, etc. - any missing validation can let an attacker force your server to call:
- internal services
- databases
- admin panels
- cloud metadata endpoints
Once the server makes the request, the attacker simply reads the response through your app.
Why Metadata Endpoints Are a Big Deal
Every cloud provider exposes a “magic” URL only reachable from inside the VM/container. Common examples:
-
AWS:
http://169.254.169.254/latest/meta-data/ -
GCP:
http://169.254.169.254/computeMetadata/v1/ -
Azure:
http://169.254.169.254/metadata/instance?api-version=2021-02-01
These endpoints give instances access to things like:
- role/instance credentials (AWS STS tokens, Azure IMDS tokens, GCP access tokens)
- network configuration
- VM instance info
- temporary signed URLs
They’re meant for internal consumption. But if an attacker can trigger a backend HTTP call, they can pull these tokens and impersonate the instance - which usually means full access to your cloud resources.
A Classic Exploitation Flow
Here’s how metadata exploitation typically happens:
1. User-controlled URL input
Example:
json{
"image": "https://example.com/avatar.png"
}
Backend fetches this image to generate a preview.
2. Attacker replaces it with metadata endpoint
urlhttp://169.254.169.254/latest/meta-data/iam/security-credentials/
3. Server fetches the URL
The cloud environment thinks your VM is making a legit request.
4. Response gets reflected back to attacker
Now they have:
- Access tokens
- IAM role names
- Temporary creds
- Possibly privileged permissions
5. They use those tokens in AWS/GCP/Azure APIs
Examples:
- List S3 buckets
- Upload malware
- Spin up cryptominers
- Dump databases
- Modify DNS and redirect domains
This chain is brutally simple and incredibly common.
Real-World Examples
You don’t have to look far:
- Capital One breach (2019) - involved SSRF to AWS metadata → IAM role theft → S3 bucket exfiltration.
- Many open bug bounty reports show the same pattern: an image fetcher, PDF service, or webhook checker allowing metadata access.
Whenever a cloud role has “too much power”, SSRF becomes catastrophic.
How to Prevent Metadata Abuse
1. Block internal IP ranges
Deny requests to:
-
169.254.169.254 -
127.0.0.1 -
Private ranges:
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
2. Only allow outbound requests to whitelisted domains
Don’t validate only by string matching - resolve the domain and check its final IP.
3. Set request timeouts
Prevents slow-loris style SSRF tunneling.
4. Use cloud protections
- AWS IMDSv2 (requires session token headers, blocks basic request tricks)
- GCP Metadata-Flavor: Google header requirement
- Azure Metadata Header: true requirement
These force clients to send specific headers attackers usually cannot forge through SSRF.
5. Least privilege IAM roles
Even if SSRF hits metadata, the stolen token should be nearly useless.
6. Avoid “URL fetcher” anti-patterns
Caching previews, fetching PDFs, or validating webhooks should always be done through:
- background workers
- strict allowlists
- hardened HTTP clients
Quick Checklist for Developers
- ❌ Don’t trust user-supplied URLs
- ✔️ Validate domains and resolve DNS
- ✔️ Block internal IP ranges
- ✔️ Enforce metadata headers
- ✔️ Keep IAM roles minimal
- ✔️ Monitor unusual metadata calls in logs
Final Thoughts
SSRF isn’t just a backend mistake - it’s a cloud security mistake. Metadata endpoints are extremely powerful, and once exposed through SSRF, attackers gain the same privileges your workload has.
If you’re building anything that fetches user-controlled URLs, treat it as a high-risk component from day one.
Album of the blog:




