
Defending Against SSRF Attacks: Production-Grade Patterns, Tools, and Cloud Hardening
Server-Side Request Forgery (SSRF) remains a top vector for cloud-native breaches, allowing attackers to pivot inside networks and exfiltrate sensitive metadata. With increased adoption of microservices and public cloud APIs, mitigating SSRF is an urgent, production-critical concern.
What Is SSRF? (With Real Code Example)
Server-Side Request Forgery (SSRF) is a vulnerability that lets an attacker make arbitrary HTTP requests from your application server. These requests can target internal resources (like metadata services or internal APIs) that are unreachable from the public internet. In cloud environments, SSRF can escalate to full infrastructure compromise—such as stealing AWS IAM credentials from the EC2 metadata API.
Here’s a simplified Node.js/Express example of an SSRF risk:
// SSRF-prone code (Node.js/Express)
const express = require('express');
const axios = require('axios');
const app = express();
app.get('/fetch', async (req, res) => {
const { url } = req.query;
try {
const response = await axios.get(url); // UNSAFE: user controls the URL
res.send(response.data);
} catch (err) {
res.status(500).send('Error fetching data');
}
});
If a user supplies http://169.254.169.254/latest/meta-data/, the server exposes its cloud credentials. Preventing SSRF means tightly restricting outbound requests and controlling URL input.
Key insight: SSRF isn’t just about HTTP—attackers can leverage DNS rebinding, redirects, and chained protocols to bypass naive filters.
Step 1: Lock Down Outbound Requests at the Application Layer
Validate and Sanitize User-Supplied URLs
Never trust direct user input for URLs. Use allowlists to restrict requests to trusted domains. In Node.js, I recommend the validator library (v13.9.0+) and strict domain comparison:
const { isURL } = require('validator');
const TRUSTED_DOMAINS = ['api.mycompany.com', 'maps.googleapis.com'];
function isTrustedUrl(url) {
try {
const parsed = new URL(url);
return TRUSTED_DOMAINS.includes(parsed.hostname);
} catch {
return false;
}
}
Reject Private IP Ranges
Implement logic to block all RFC1918 and link-local ranges (e.g., 10.0.0.0/8, 169.254.0.0/16). Use the ip or netaddr package to parse and check IPs after DNS resolution:
const ip = require('ip');
function isPrivateIp(ipAddress) {
return ip.isPrivate(ipAddress) || ipAddress.startsWith('169.254.');
}
Key insight: Application-layer allowlists are your first—and sometimes only—line of defense against SSRF.
Step 2: Enforce Network Egress Controls for Defense-in-Depth
Cloud VPC Security Group/Egress Firewall Rules
At the network layer, you must restrict egress traffic. In AWS, set restrictive VPC security group egress rules:
# Terraform example: only allow egress to specific external API
resource "aws_security_group" "app_egress" {
name = "app-egress"
vpc_id = aws_vpc.main.id
egress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["34.120.0.0/16"] # Google Maps API
}
}
In Kubernetes, use Cilium (v1.13+) or Calico (v3.25+) NetworkPolicies to restrict Pod egress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-egress
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 34.120.0.0/16
ports:
- protocol: TCP
port: 443
Key insight: Even if application code is vulnerable, network egress restrictions prevent lateral movement and cloud metadata abuse.
Step 3: Harden Cloud Metadata Endpoints
Block Access to Metadata IPs (e.g., 169.254.169.254)
On AWS, GCP, and Azure, the instance metadata service is exposed at a well-known link-local IP. Always block this address from application containers/processes:
- AWS: Use Instance Metadata Service v2 (IMDSv2) and block HTTP traffic to 169.254.169.254 at the host/ENI level.
- GCP: Remove
cloud-platformscopes from default service accounts. Use Metadata Concealment with GKE. - Kubernetes: With Cilium, block egress to 169.254.169.254 using a policy:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: block-metadata
spec:
endpointSelector: {}
egress:
- toCIDR:
- 169.254.169.254/32
toPorts:
- ports:
- port: '80'
protocol: TCP
OS-Level Firewalling
Set up iptables rules for bare-metal environments:
iptables -A OUTPUT -d 169.254.169.254 -j DROP
Key insight: Metadata endpoints are high-value SSRF targets; block access by default, not just by policy.
Step 4: Detect and Monitor SSRF Attempts in Production
Log and Alert on Suspicious Outbound Requests
Instrument outbound HTTP libraries (axios, requests, http.client) to record destination URLs, request metadata, and user context. For Node.js, use Winston or Pino for structured logging:
logger.info({
event: 'outbound_request',
url: requestedUrl,
user: req.user?.id,
timestamp: Date.now()
});
Forward logs to Datadog (v2.x+) or Splunk for rule-based alerting on patterns like 169.254.169.254 or internal subnets.
Enable Cloud-Native Threat Detection
- AWS GuardDuty: Detects suspicious calls to the EC2 metadata API.
- Azure Defender for Cloud: Monitors and alerts on metadata service access.
- GCP Security Command Center: Flags abnormal egress to metadata or internal IPs.
Set actionable alerts for any non-whitelisted egress destination.
Key insight: Without visibility, you cannot distinguish targeted SSRF attempts from legitimate service calls—instrumentation is required.
Step 5: Use SSRF-Resistant Libraries and Frameworks
Prefer Hardened HTTP Clients
Some modern HTTP libraries explicitly support SSRF prevention. For example, got (v12.6+) in Node.js lets you control DNS resolution and restrict IP ranges:
const got = require('got');
const safeRequest = got.extend({
dnsCache: true,
hooks: {
beforeRequest: [options => {
// Reject private IPs here
}]
}
});
Framework-Level Controls
- Spring Security (v6.0+): Enforce URL allowlists for RestTemplate/WebClient.
- .NET: Use
SocketsHttpHandler.ConnectCallbackto validate IP addresses post-DNS. - Python Requests: Use
requests-toolbeltto wrap/validate connections.
Key insight: Leverage native library support for outbound request validation whenever possible—never roll your own DNS/IP parsing.
SSRF Mitigation Techniques: Tools and Trade-offs
| Tool/Technique | Strengths | Weaknesses / Trade-offs |
|---|---|---|
| App-Layer URL Allowlist | Fine-grained control; easy to audit | Bypassable via DNS rebinding, misparsing |
| Network Egress Firewall | Stops post-exploit movement; cloud-native support | Can block legitimate traffic if not maintained |
| Metadata Endpoint Block | Prevents cloud credential theft | Needs OS/network support; can break cloud agents |
| Cloud Threat Detection | Real-time alerting; integrates with SIEM | May generate false positives; reactive not proactive |
| SSRF-Aware HTTP Clients | First-class SSRF controls; reduces dev error risk | Limited language/framework coverage |
| Web App Firewall (WAF) | Quick win; blocks common payloads | Evasion possible; doesn’t mitigate all SSRF forms |
Key insight: No single technique is sufficient—layer defense-in-depth across code, network, and cloud runtime.
Frequently Asked Questions
Q: How can I test my app for SSRF vulnerabilities?
A: Use open-source tools like SSRFmap or Burp Suite’s SSRF scanner. Try sending requests to internal IPs (e.g., http://169.254.169.254/) and check if the response is relayed. Always test in a controlled, non-production environment.
Q: What makes SSRF especially dangerous in cloud environments? A: In cloud platforms, SSRF can access metadata APIs (like AWS IMDS), leaking credentials that allow full control over your infrastructure—far exceeding typical web app compromise. That’s why cloud providers and the OWASP Top 10 highlight SSRF as a critical risk.
Q: Can Web Application Firewalls fully protect against SSRF? A: WAFs can block obvious SSRF payloads but cannot stop advanced attacks using DNS rebinding, protocol chaining, or custom encodings. Combine WAFs with app, network, and cloud controls for robust SSRF defense.
Key Takeaways
- Always validate and allowlist outbound URLs at the application level—never trust user input for HTTP requests.
- Lock down network egress with VPC security groups, Kubernetes NetworkPolicies, or host firewalls to block unauthorized destinations.
- Explicitly block access to cloud metadata endpoints (e.g., 169.254.169.254) from app containers, with cloud-native or OS-level rules.
- Instrument outbound requests and enable cloud-native threat detection tools (GuardDuty, Security Command Center) for real-time SSRF monitoring.
- Prefer SSRF-aware HTTP clients and framework-level outbound request controls to minimize developer error.
- Defense-in-depth is non-negotiable—combine app, network, cloud, and monitoring layers for production-grade SSRF mitigation.


