Server-Side Request Forgery: When Your Server Becomes the Attacker
Server-side request forgery was significant enough to earn its own dedicated category in the OWASP Top 10 in 2021. The reason is straightforward: in a cloud-native world where applications routinely fetch URLs, parse webhooks, and integrate with external services, SSRF transforms a legitimate server into an attacker's proxy — one that sits inside the network perimeter with access to internal services, cloud metadata, and infrastructure that is invisible from the outside.
The vulnerability itself is simple. An application accepts a URL from the user and fetches it server-side. The attacker provides a URL pointing to an internal resource, and the server dutifully retrieves it. What makes SSRF devastating is the context: the server has network access that the attacker does not, and in cloud environments, a single SSRF vulnerability can escalate to full infrastructure compromise.
How SSRF Works
Any feature where the server makes an HTTP request based on user-supplied input is a potential SSRF vector. Common examples include:
- URL preview / link unfurling — Fetching metadata, titles, and thumbnails from user-provided URLs
- Webhook delivery configuration — Allowing users to specify callback URLs
- File imports from URL — Importing images, documents, or data from a user-specified URL
- PDF generation — Server-side rendering of HTML that may include external resources
- API integrations — Proxy endpoints that forward requests to user-configured services
The basic exploit is straightforward:
POST /api/fetch-url
Content-Type: application/json
{
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
}
Instead of fetching a public website, the server fetches its own cloud metadata endpoint and returns the response to the attacker. That response contains temporary security credentials that grant access to the cloud provider's API.
Internal Network Access
Most applications run behind a firewall or within a virtual private network. Internal services — databases, admin panels, monitoring dashboards, message queues — are accessible from the application server but not from the internet. SSRF bridges that gap.
# Scan for internal services
http://10.0.0.1:8080/
http://10.0.0.2:6379/ (Redis)
http://10.0.0.3:9200/ (Elasticsearch)
http://10.0.0.4:8500/ (Consul)
An attacker can use SSRF to port-scan the internal network, discover services, and interact with them. Many internal services have no authentication because they were designed to be accessed only from within the trusted network. Redis, Elasticsearch, Memcached, and various admin interfaces are frequently deployed without access controls, making them trivially exploitable via SSRF.
Cloud Metadata Exploitation
Cloud metadata services are the highest-value SSRF target. Every major cloud provider exposes an instance metadata endpoint at 169.254.169.254 (a link-local address accessible only from the instance itself). This endpoint provides:
- Temporary IAM credentials — Access keys and secret keys for the instance's role
- User data scripts — Startup scripts that often contain hardcoded secrets
- Network configuration — Internal IPs, VPC details, and security group information
- Instance identity documents — Signed tokens that prove instance identity
With IAM credentials obtained through SSRF, an attacker can:
- Access cloud storage buckets containing customer data
- Read secrets from key management services
- Modify infrastructure through the cloud provider's API
- Pivot to other services within the cloud account
- Create new resources (instances, users) for persistence
In one penetration test, a tester exploited an SSRF vulnerability in a PDF generation feature. The application rendered user-supplied HTML to PDF, and the tester included an iframe pointing to the metadata endpoint. The rendered PDF contained the instance's IAM credentials, which had permissions to access the production database, customer file storage, and deployment pipeline. From a single SSRF vulnerability, the entire cloud infrastructure was compromised.
Protocol Smuggling
SSRF is not limited to HTTP. If the application's HTTP library supports other URL schemes, attackers can interact with non-HTTP services:
file:///etc/passwd— Read local files from the server's filesystemgopher://— Craft arbitrary TCP packets, enabling interaction with Redis, SMTP, and other protocolsdict://— Interact with dictionary services and potentially leak informationftp://— Access FTP services on the internal network
The gopher:// scheme is particularly dangerous because it allows sending raw data to any TCP port. An attacker can craft a gopher URL that sends valid Redis commands:
gopher://10.0.0.2:6379/_SET%20pwned%20true%0D%0A
This writes data to a Redis instance on the internal network, potentially enabling remote code execution through Redis's module loading or Lua scripting capabilities.
Real-World Attack Scenarios
Cloud Credential Theft via Webhook Configuration
A SaaS platform allowed customers to configure webhook URLs for event notifications. When an event occurred, the server sent a POST request to the configured URL. A tester configured a webhook pointing to:
http://169.254.169.254/latest/meta-data/iam/security-credentials/app-role
The platform logged webhook delivery failures, including the response body. The response body contained the instance's IAM credentials. These credentials had broad permissions — the application role needed access to storage, database, and messaging services. Within an hour, the tester had mapped the entire cloud infrastructure and demonstrated access to production data stores.
Internal Service Exploitation Through Image Processing
A content management platform allowed users to specify a URL for their profile image. The server downloaded the image, resized it, and stored it. A tester provided URLs pointing to internal services:
http://10.0.0.5:9200/_cat/indices
The Elasticsearch instance on the internal network had no authentication. Through the image URL feature (which returned error pages as images), the tester enumerated all indices, retrieved index mappings, and ultimately extracted sensitive data. The "image download" feature had become a full proxy into the internal network.
Bypassing IP Restrictions Through DNS Rebinding
An application implemented SSRF protection by resolving the URL's hostname and checking that the IP address was not internal. A tester set up a DNS server that responded with an external IP address on the first query (passing the validation check) and an internal IP address on subsequent queries (when the server actually made the request).
This DNS rebinding attack completely bypassed the IP validation. The application resolved the hostname twice — once to validate, once to connect — and the DNS responses were different each time. The window between validation and connection was all the attacker needed.
Common Bypass Techniques
Attackers have developed numerous techniques to bypass SSRF protections:
IP address encoding:
http://127.0.0.1 → Standard
http://2130706433 → Decimal
http://0x7f000001 → Hexadecimal
http://0177.0.0.1 → Octal
http://127.1 → Abbreviated
http://[::1] → IPv6 localhost
http://0.0.0.0 → Binds to all interfaces
http://127.0.0.1.nip.io → DNS that resolves to 127.0.0.1
URL parsing confusion:
http://attacker.com@169.254.169.254/
http://169.254.169.254#@attacker.com
http://169.254.169.254%23@attacker.com
Redirect-based bypass:
An attacker hosts a page at https://evil.com/redirect that returns a 302 redirect to http://169.254.169.254/. The application validates that evil.com is not an internal address and follows the redirect to the metadata endpoint.
DNS pinning race conditions: Even if the application validates the resolved IP, a race condition between validation and connection allows the DNS record to change.
Prevention Strategies
Allowlists Over Blocklists
Blocklists are fundamentally flawed for SSRF prevention. There are too many ways to represent internal IP addresses, and new bypass techniques emerge regularly. Instead, maintain an allowlist of permitted destinations:
ALLOWED_HOSTS = {"api.trusted-service.com", "cdn.partner.com"}
ALLOWED_SCHEMES = {"https"}
def validate_url(url: str) -> bool:
parsed = urlparse(url)
if parsed.scheme not in ALLOWED_SCHEMES:
return False
if parsed.hostname not in ALLOWED_HOSTS:
return False
return TrueIf an allowlist is too restrictive for your use case (e.g., a URL preview feature that must fetch arbitrary URLs), combine multiple defensive layers.
URL Validation and Sanitization
When you must accept arbitrary URLs:
- Parse the URL using a well-tested library — do not use regex
- Resolve the hostname to an IP address before making the request
- Validate the resolved IP against a blocklist of internal ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, 169.254.0.0/16, ::1)
- Disable redirects or re-validate after each redirect
- Restrict URL schemes to
httpsonly — disablefile,gopher,dict,ftp - Re-resolve and re-validate immediately before connecting to prevent DNS rebinding
import ipaddress
import socket
def is_internal_ip(ip_str: str) -> bool:
ip = ipaddress.ip_address(ip_str)
return (
ip.is_private or
ip.is_loopback or
ip.is_link_local or
ip.is_reserved
)
def safe_fetch(url: str) -> Response:
parsed = urlparse(url)
if parsed.scheme not in ("http", "https"):
raise ValueError("Invalid scheme")
# Resolve hostname and validate IP
ip = socket.gethostbyname(parsed.hostname)
if is_internal_ip(ip):
raise ValueError("Internal IP not allowed")
# Connect to the resolved IP directly to prevent DNS rebinding
return requests.get(url, allow_redirects=False, timeout=5)Network Segmentation
The most effective defense against SSRF impact is network segmentation. Application servers should not have network access to sensitive internal services:
- Place application servers in a DMZ with limited outbound access
- Use security groups / firewall rules to restrict which internal services each application can reach
- Block access to 169.254.169.254 from application servers using iptables or cloud firewall rules
- Use IMDSv2 (AWS) or equivalent, which requires a PUT request with a hop limit of 1, preventing SSRF exploitation of the metadata service
Cloud-Specific Mitigations
AWS IMDSv2: Requires a token obtained via a PUT request with a TTL header. SSRF through libraries that only support GET cannot obtain the token. Enable IMDSv2 and disable IMDSv1 on all instances.
GCP: Use the Metadata-Flavor: Google header requirement (similar to IMDSv2). Assign minimal IAM roles to instance service accounts.
Azure: Use managed identities with minimal permissions. Restrict metadata endpoint access through network policies.
Isolated Fetch Services
For features that must fetch arbitrary URLs (link previews, webhook testing), run the fetch operation in an isolated environment:
- A separate container or function with no access to the internal network
- A dedicated egress proxy that enforces URL policies
- A sandboxed environment with no cloud metadata access
This architectural separation ensures that even if SSRF occurs, the attacker gains access to nothing of value.
Testing for SSRF
Effective SSRF testing involves:
- Identify all features that fetch URLs — webhooks, imports, image downloads, link previews, PDF generation, API proxy endpoints
- Test with internal addresses — 127.0.0.1, 10.x.x.x, 169.254.169.254, IPv6 equivalents
- Test bypass techniques — IP encoding variations, DNS rebinding, open redirects
- Test non-HTTP schemes — file://, gopher://, dict://
- Test blind SSRF — Use an out-of-band callback server to detect requests even when the response is not returned
- Verify network segmentation — Even if SSRF exists, confirm that the server cannot reach sensitive services
Blind SSRF (where the server makes the request but does not return the response) is common and still dangerous. The server can be used to port-scan internal networks, interact with services, and exfiltrate data through DNS queries.
Key Takeaways
SSRF is an architectural vulnerability, not just a code bug. In cloud environments, a single SSRF vulnerability can cascade into complete infrastructure compromise. Defense requires multiple layers:
- Maintain strict allowlists of permitted outbound destinations
- Validate and re-validate URLs, including resolved IP addresses
- Restrict URL schemes to HTTPS only
- Segment your network so application servers cannot reach sensitive internal services
- Enable IMDSv2 and disable legacy metadata endpoints
- Run URL-fetching features in isolated environments with minimal network access
- Monitor outbound requests for anomalous destinations
The attack surface grows with every feature that fetches external content. Each URL input is a potential portal into your internal network.
Need your application tested for server-side request forgery? Get in touch.