In 2019, a single request stole the personal data of over 100 million people from one of the biggest banks in America.
No malware. No stolen password. No one kicked down a door. The attacker just asked a server a question, and the server, trying to be helpful, answered with the keys to the vault.
The bug behind it is called SSRF, and once you see how it works, you start noticing the setup for it everywhere. I spent this week learning it hands-on, and I want to walk you through it the way it finally made sense to me, with that real breach as the destination.
First, Forget "Breaking In"
When most people imagine a server getting hacked, they picture someone forcing their way inside. SSRF is the opposite of that, and that's exactly why it's so easy to miss.
You never get in. You convince the server to go somewhere for you.
Here's the picture that made it click. Hold onto it, because we're coming back to it.
You're standing outside a corporate building. Locked doors. Security at the entrance. Inside, down some hallway you'll never walk, there's a back office full of sensitive files. You want those files. You are not getting past that front desk.
But there's a mailroom clerk inside. He walks the whole building all day. Nobody questions him, he's obviously staff. So you stop him on his smoke break and hand him a note: "Run to the back office, grab the file on the desk, bring it out to me."
And he does. Because he can go where you can't, and because nobody inside thinks to check whether his errands are legit.
You never entered. You broke nothing. You just borrowed someone with better access than you.
That is the entire idea of SSRF. The server is the clerk.
Now the Technical Version
Say a shopping site has a "check stock" button. Behind the scenes, when you click it, the server reaches out to an internal inventory service to get the number:
POST /product/stock
stockApi=http://stock.internal-shop.net/check?productId=6
See that stockApi value? The server takes that URL and fetches it for you. The developer assumed it would only ever point at their own inventory service.
But what if you change it?
stockApi=http://localhost/admin
Now you've handed the clerk a different note. Instead of fetching inventory, the server fetches its own admin panel, a page you could never load yourself from the outside, and hands you back the contents.
That's the whole move. You didn't attack the admin panel. You asked the server to go read it for you, and it did, because the request came from inside the house.
The Part That Turns "Annoying" Into "Catastrophic"
Here's what I didn't expect. Why does that admin panel even open up for a request from localhost? Shouldn't it still require a login?
Often, no. And the reason is a quiet assumption baked into how internal systems get built:
"Only trusted internal services can reach this machine. So why bother locking it?"
Internal admin panels, dashboards, and APIs are frequently left wide open. No password. Default settings. Old, unpatched software. Because everyone assumed the network itself was the wall, nobody untrusted could ever reach these things, so why waste effort hardening them.
SSRF knocks the wall down. The second you can make an outward-facing server pass notes inward, every one of those unlocked internal doors is suddenly reachable. And they were built on the belief that this day would never come.
The Case Study: How a Bank Lost 100 Million Records
Now we can walk through the real one, and you'll recognize every step.
In 2019, a major US bank ran its infrastructure in the cloud. Like a lot of companies, they had a web application firewall sitting in front of their servers to filter bad traffic.
That firewall had an SSRF vulnerability. An attacker could make it send requests on their behalf. The clerk, in other words.
Now, here's the cloud-specific twist. Servers running in the cloud have a special internal address, the same one on nearly every cloud instance:
http://169.254.169.254/
This is the metadata service. It's meant for the server to ask questions about itself. And one of the things it will happily tell anyone who asks from the right place is: the server's own access credentials. The temporary keys that let that machine talk to the rest of the company's cloud account.
You can see where this goes.
- The attacker found the SSRF in the firewall. (Found a clerk.)
-
They made it request
http://169.254.169.254/.... (Handed over the note.) - The metadata service, seeing a request from a legitimate internal server, returned that server's cloud credentials. (The clerk fetched the file.)
- With those credentials, the attacker reached into the cloud storage and pulled out the data of over 100 million people.
No password was cracked. No one phished an employee. The system worked exactly as designed. It just trusted the wrong request, and that trust was the whole vulnerability.
This Is Not an Old, Solved Problem
I came into security assuming bugs like this were mostly legacy, patched out of modern frameworks years ago. SSRF is the opposite. It's arguably more dangerous today than ever, and it's because of how we build things now:
- Microservices mean an app is dozens of small internal services calling each other over HTTP. Every one of those internal calls is a door the clerk can be sent to.
-
The cloud means that
169.254.169.254metadata endpoint is sitting on nearly every server you deploy. - "Fetch this URL" features are everywhere now: webhooks, link previews, "import from URL", avatar fetchers, PDF generators. Every single one is a potential clerk waiting for a note.
The flaw didn't disappear. It moved into the architecture we all use now.
Why I'm Personally Obsessed With This One
I'm working toward AI and LLM security, and SSRF turned out to be the most important thing I could have learned for it.
Think about what an AI agent actually does all day. It fetches URLs. It calls tools and APIs. It retrieves documents on your behalf. That is the mailroom clerk, rebuilt in software and handed a lot more autonomy.
So the modern version of this attack writes itself: instead of changing a stockApi parameter, you plant an instruction in text the model will read, "go fetch this internal address", and the agent, trusted inside the network, does it. Same bug. Same clerk. The note is just written in English now instead of a URL field.
Every technique I picked up chasing these labs, reaching localhost, hitting the metadata endpoint, slipping past filters, points straight at how you attack and defend AI agents.
So What Do You Actually Do About It?
If you build anything that fetches a URL on the server side, three habits shut most of this down:
- Allowlist, don't blacklist. Decide the short list of places your server is allowed to fetch, and reject everything else. Trying to block all the bad addresses is a losing game (that's a whole post on its own).
- Validate where the URL actually resolves, not just how it's spelled. Block private IP ranges and that metadata address, and re-check after any redirect.
- Don't hand the raw fetched response back to the user, and use the cloud's hardened metadata mode (IMDSv2) so a naive request can't just walk away with credentials.
The Takeaway
SSRF isn't about breaking in. It's about noticing that the server you're talking to has a trusted seat at a table you weren't invited to, and realizing you can get it to pass notes for you.
Once that clicks, you can't unsee it. Every "the server fetches this for you" feature starts to look like a clerk waiting for the wrong instructions.
I'm learning this stuff in public on the way to AI security. If a different analogy or breach finally made SSRF make sense for you, I'd genuinely like to hear it in the comments.
Top comments (0)