Sending the teller to the back room
Watch it happen
Mallory asks the teller to fetch a file from an address. She gives the address of the staff-only back room, and the teller brings back the keys.
The teller offers a service: “give me an address and I’ll fetch it for you.” Alice walks up to use it. Mallory comes in behind her.
In bank terms and app terms
| In the bank | In your app |
|---|---|
Are you exposed?
Your server fetches a URL that came from a user: avatar import, webhook URL, “preview this link”, proxy or screenshot features. Your app runs in the cloud (AWS, GCP, etc.) and the metadata service is reachable from the app. You only block obvious words like “localhost” and you follow redirects automatically.
Allow only specific hostnames you trust. Do not try to block bad ones. Resolve the address yourself, reject private, loopback and link-local IPs, connect to the exact IP you checked (DNS can change), and re-check every redirect. On AWS require IMDSv2 (a plain URL fetch can’t get a token) and give the server the least permissions possible, so stolen keys aren’t worth much.
It has happened to real companies
Capital One (2019) — An attacker got in through a misconfigured web application firewall on Capital One's AWS setup (US Department of Justice), and Krebs's analysis describes the firewall being tricked into relaying requests to a back-end resource on AWS, which is the server-side request forgery pattern. Capital One reported that information on about 100 million people in the US and 6 million in Canada was affected. The attacker was convicted in 2022 of wire fraud and computer intrusion charges, and the US regulator OCC fined Capital One $80 million in 2020 for failing to establish effective risk assessment before moving major IT operations to the cloud.
Shopify — Researcher @0xacb found an SSRF in the screenshot feature of Shopify Exchange that gave root access to any container in one infrastructure subset (not Shopify core). Shopify disabled the service within an hour, paid a $25,000 bounty and added a proxy that blocks access to instance metadata.
What it looks like in code
// BAD: Fetches any URL provided by the user
export async function GET(request: Request) {
const url = new URL(request.url).searchParams.get("url")
const response = await fetch(url!) // No validation
const data = await response.text()
return new Response(data)
}
Ask your AI tool to fix it
Paste this into Cursor, Claude, Lovable, Bolt or whatever you build with.
Find every place the server fetches a URL supplied by a user (fetch, axios, request, image or webhook importers, link previews). Add an allowlist of permitted hostnames, resolve DNS and reject private, loopback and link-local IP ranges (including 169.254.169.254), disable automatic redirects or re-validate each hop, and set a short timeout. List the changes.Where this comes from
The facts, figures and fixes on this page were checked against these sources on 25 Oct 2026. They are linked so you can check for yourself.
- Server-Side Request Forgery Prevention Cheat SheetOWASPAllowlists over blocklists, resolve and check the IP, DNS rebinding, metadata ranges, IMDSv2
- Use the Instance Metadata Service to access instance metadataAmazon Web ServicesIMDSv2 needs a session token; 169.254.169.254; setting token use to required
- What We Can Learn from the Capital One HackKrebs on SecurityCapital One's firewall tricked into relaying requests to the AWS metadata service (SSRF)
- 2019 Cyber Incident: FactsCapital OneAbout 100 million people in the US and 6 million in Canada affected
- OCC Assesses $80 Million Civil Money Penalty Against Capital OneUS Office of the Comptroller of the Currency2020 $80 million fine for weak risk assessment before moving IT to the cloud
- One Million Dollars in Bug BountiesShopify EngineeringExchange screenshot SSRF, $25,000 bounty, disabled within an hour, metadata proxy added
Spot a mistake or something out of date? Report a correction · How these guides are made and checked
The free, open-source scanner checks for most of the problems in these guides.