Hex Security is now ParameterWe're at Black Hat USA 2026

Parameter
← All posts
5 min readHuzaifa Ahmad

SSRF to cloud takeover: how one URL field becomes credential theft

Attack TechniquesCloud Security
A stream of voxel cubes bending back inward from a cloud toward a locked server vault, depicting a request redirected to an internal metadata endpoint

Server-side request forgery has one of the widest gaps between how boring it looks and how badly it ends. The vulnerable feature is almost always something mundane: a "preview this link" box, an avatar-by-URL uploader, a webhook, a document importer. Something that takes a URL from the user and has the server go fetch it. On paper it's a convenience. In practice it's you handing an attacker the keys to make requests from inside your network, and in a cloud environment that frequently means handing over live credentials.

The core of the bug

SSRF happens when an application accepts a URL or hostname from a user and makes a server-side request to it. The attacker can't reach your internal network directly, but your server can, and once it's fetching URLs on the attacker's behalf, the attacker is driving. That's the entire mechanism: a feature built to fetch a URL for you, pointed somewhere it was never meant to reach.

OWASP promoted SSRF to its own Top 10 category for a reason. The shift to cloud and microservices turned it from a medium-severity curiosity ("an attacker can port-scan your internal network") into a reliable route to full compromise. The thing that changed the severity math is a single address.

Why the cloud made it critical: the metadata endpoint

Every major cloud provider exposes an instance metadata service at the link-local address 169.254.169.254. It's how a running instance learns about itself: its role, its region, and, crucially, its temporary credentials. On a host still running the older, unauthenticated version of that service, a single GET request is enough:

curl http://169.254.169.254/latest/meta-data/iam/security-credentials/app-role
# -> AccessKeyId, SecretAccessKey, Token  (valid right now)

The attacker can't hit that address from the outside. But a server with an SSRF bug can, and it will happily fetch it on command. That is the chain: a "preview this link" box, pointed at the metadata endpoint, returns the temporary IAM credentials the instance was using. It's the same class of mistake behind one of the most well-known cloud breaches of the last decade, and it still works against misconfigured instances today. The other major clouds expose equivalents; some require a special request header, but an SSRF that can influence headers can often satisfy that too.

Once an attacker holds those credentials, they're no longer poking at your network from outside. They're inside it, authenticated as your workload, with whatever permissions that role was granted, which in most environments is more than anyone remembers granting.

A user request enters a server, which then sends a request to a cloud metadata endpoint that returns keys back along the path.The chain: the attacker can't reach the metadata endpoint, but the vulnerable server can, and it hands the credentials back.

How attackers escalate a "harmless" fetch

Finding SSRF starts with pointing the parameter inward, at 127.0.0.1, localhost, 169.254.169.254, and the private ranges, and watching for tells. Even when nothing gets echoed back, differences in response time, status code, or error text leak whether an internal port is open. When the response never returns at all ("blind" SSRF), attackers use an out-of-band canary: a hostname they control, watching for the DNS or HTTP callback that proves the server connected.

Naive defenses fall to a standard bypass arsenal almost immediately:

  • Alternate IP encodings. 2130706433, 0x7f000001, and 0177.0.0.1 all mean 127.0.0.1. A blocklist checking for the literal string 127.0.0.1 sees none of them.
  • Redirect smuggling. Point the fetcher at a host you control that responds with a 302 to 169.254.169.254. Many fetchers follow redirects blindly, so the filter validates the harmless first URL and the client walks itself to the metadata endpoint.
  • DNS rebinding. A hostname resolves to a public IP when your filter checks it, then to a private IP a moment later when the HTTP client actually connects.
  • Unexpected schemes. file://, gopher://, and dict:// open up file reads and protocol smuggling that a URL-shaped mental model never anticipates.

The through-line: every one of these defeats a filter that treats SSRF as a string-parsing problem.

How to actually break the chain

A server whose only open path passes through a gate to one allowed destination, with other destinations blocked behind walls.Allowlist plus resolve-and-pin: default-deny, with exactly the destinations you need explicitly permitted.

Blocklists lose this fight: there are too many ways to spell an internal address. The pattern that holds up is an allowlist plus resolve-and-pin:

  1. Allow only what you need. Permit specific schemes and a known set of destination hosts. Reject everything else by default rather than trying to enumerate what's dangerous.
  2. Resolve the hostname yourself, then pin it. Look up the address, check it against loopback, private, and link-local ranges, and connect to that exact IP. Don't let the HTTP client re-resolve, or DNS rebinding walks straight past your check.
  3. Disable schemes you don't use. Turn off file://, gopher://, dict://, and ftp://.
  4. Fix it at the platform layer too. Enforce the token-based, hop-limited version of your metadata service, and block egress to 169.254.169.254 from workloads that never legitimately need it. Defense in depth means the app-layer bug doesn't automatically become credential theft.
  5. Never echo the raw upstream response. Return only the fields you intended, so a successful internal fetch doesn't leak its body back to the attacker.

SSRF is a trust bug, not a parsing bug. The fix is never a cleverer regex on the URL; it's deciding, explicitly and server-side, the short list of places your server is allowed to talk to, and refusing the rest.

Why this is hard to catch on a schedule

SSRF is the kind of finding that's trivial to introduce and easy to miss. It rides in on a feature that looks like product work (link previews, imports, webhooks), so it doesn't announce itself as a security change, and it often isn't reachable until a specific input shape triggers it. An annual pentest might catch the instance that exists during its two-week window; it won't catch the "preview URL" feature a team ships the following month.

This is where continuous, validated testing earns its place. Parameter's agents don't just flag that a URL parameter might be forgeable; they attempt the chain the way an attacker would, follow the redirect, reach for the metadata endpoint, and confirm whether real credentials come back. What lands in your queue is a validated finding with the exact request and the fix, not a "possible SSRF" you have to reproduce yourself.

For the bigger-picture argument on why testing has to run at the cadence you ship, see continuous penetration testing vs. annual pentests.