hunt-ssrf – Security skill for AI agents
Hunting skill for ssrf vulnerabilities.
Install the hunt-ssrf skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-ssrf-e1af1.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /hunt-ssrf – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-ssrf-e1af1.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $hunt-ssrf – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-ssrf-e1af1.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /hunt-ssrf – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-ssrf-e1af1.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /hunt-ssrf – then describe the task you want done.
SKILL.md content
> ⚠️ AUTHORIZED USE ONLY
> This skill is for educational purposes or authorized security assessments only.
> You must have explicit, written permission from the system owner before using this tool.
> Misuse of this tool is illegal and strictly prohibited.
> Mandatory confirmation gate
> Before running any command that probes, exploits, changes, persists on, extracts data from, or attempts credential access against a target:
> 1. Ask the user to state the exact target URL, IP, account, or resource.
> 2. Ask the user to confirm written authorization and the permitted scope.
> 3. Show the exact command(s) and explain their expected effect.
> 4. Wait for explicit confirmation in the current conversation.
>
> Without that confirmation, remain read-only and provide defensive guidance only. Prefer a sandbox, disposable VM, or controlled lab.
Crown Jewel Targets
SSRF is highest-value when the target runs on cloud infrastructure (AWS, GCP, Azure) where metadata services expose credentials, or when the server sits inside a complex internal network (Kubernetes clusters, microservice meshes, internal APIs). Priority targets:
- Cloud-hosted SaaS products (GCP metadata at
169.254.169.254ormetadata.google.internal, AWS IMDSv1) - Kubernetes/orchestration platforms — aggregated API servers, metrics-server, kubelet endpoints expose privileged cluster operations
- Internal developer tooling — CI/CD, workflow orchestration (Flyte, Argo), admin panels not exposed externally
- Link preview / URL fetching features — Reddit-style preview APIs, Slack-style unfurling, media processors
- Dataset/file import pipelines — anything that fetches remote URLs on behalf of a user
- Enterprise self-hosted software (GitHub Enterprise, GitLab) — SSRF frequently chains to RCE via internal services
Payouts are highest when SSRF reaches: cloud credentials → account takeover, internal admin APIs → data exfil, or chains to RCE.
---
OOB-Or-It-Didn't-Happen Gate (Read First)
Claims of blind SSRF require an out-of-band (OOB) confirmation. Always. No exceptions.
OOB means: a Burp Collaborator domain, an interactsh-client listener, a canarytoken, or any DNS+HTTP receiver you control that confirms the server actually made an outbound network connection on your behalf.
What is NOT confirmation of SSRF
- The server echoing your URL back in an error message. Example:
"The Web application at http://evil.example.com/x could not be found"— this is the server formatting your input into an error string, NOT making an outbound HTTP request. The error came from string formatting, not from network failure. - The server returning a different status code for an external URL vs
localhost. Different error responses can come from URL-scheme validators, not from actual fetching. - A delayed response when the URL is sent. Delay can come from DNS resolution attempts within the parser, not from completed HTTP fetches.
What IS confirmation of SSRF
- A unique DNS lookup confirms resolution only; attribute it to the target rather than a scanner/resolver, and do not claim an HTTP fetch from DNS alone.
- An HTTP request to your Collaborator HTTP endpoint with the server's source IP and User-Agent.
- For SSRF in JavaScript-execution contexts (PDF renderers, headless browsers), a fetch from the server to your callback URL.
Default workflow
1. Plant the Collaborator payload first. Sub-tagging (dlsrcurl.<collab>,
import.<collab>) only works if your listener actually reports the queried
subdomain back to you — verify that before relying on it. Burp's
get_collaborator_interactions keys results by payload ID, not by subdomain,
so several sub-tags generated from one payload are indistinguishable in the
output. When that is the case, **generate a fresh payload per candidate
parameter** and send exactly one request per payload.
2. Send the request to the target endpoint.
3. Wait 30–120 seconds, then poll the OOB listener.
4. Only after a confirmed callback do you claim SSRF.
5. If no callbacks arrive, report this attempt as unconfirmed; egress filtering, asynchronous work or listener failure can produce false negatives. URL reflection alone remains insufficient.
Lesson from a authorized engagement: SharePoint's /_layouts/15/download.aspx?SourceUrl= returned 500 with the title "The Web application at <attacker-URL> could not be found". Initial scan flagged this as SSRF (server clearly processed the URL). 38 Collaborator-tagged payloads across 12+ URL-accepting parameters yielded zero DNS or HTTP interactions. The "echo" was client-side error-string formatting; the server never made an outbound HTTP request. The path is actually an SP-internal SPFile/SPWebApplication resolver, not a generic URL fetcher. Reporting this as SSRF would have been N/A'd at triage.
Attribute the callback to ONE parameter before reporting
A callback proves the server made a request. It does not tell you which
parameter caused it, and the fix depends entirely on that.
BAD — four candidate fields, one payload, fired in one batch
-> callbacks arrive, attribution impossible, retest required
GOOD — fresh payload per field, one request each, poll between
url -> callbacks <- this is the sink
apiUrl -> none
endpoint -> none
target -> noneRun the negative control. A parameter that produces *no* callback is evidence,
and it belongs in the report — it is what lets the client fix the right field
instead of allowlisting the wrong one.
Lesson from an authorized engagement. A server-side request-forwarding endpoint
accepted both url and apiUrl. The application's own stored config used apiUrl,
so that was the obvious suspect — but apiUrl was inert and **url was the live
sink**.
Batch-firing both had produced callbacks with no attribution; only per-payload
isolation identified the real parameter. A report naming apiUrl would have sent
the client to patch a field that does nothing.
Blind vs full-read — establish which before scoring
After a callback confirms the request leaves the server, **check whether the
upstream response body is returned to you.** These are different findings:
- Blind (callback only, no body): assess according to the program policy and concrete reachable impact; no universal never-submit rule applies.
- Full-read (upstream body in the response): substantially higher severity —
read arbitrary internal endpoints directly.
# one request settles it: fetch something with a known, recognisable body
-d '{"url":"https://example.com/"}'
# {"statusCode":200,"data":"<!doctype html>...<title>Example Domain</title>..."}
# ^ body returned = full-read, not blindAlso body-diff a known-internal target against a known-external one. A **distinct
status** on a link-local address (e.g. 401 from 169.254.169.254 where every
other target returns 200) could be a validator, proxy or upstream service response. Status differences alone do not identify metadata or prove internal reachability.
---
Attack Surface Signals
URL Patterns to Hunt
/api/*/preview
/api/*/fetch
/api/*/import
/api/*/webhook
/api/*/proxy
/api/*/render
/api/*/link
/api/*/screenshot
/api/*/export
/api/*/validate
?url=
?uri=
?endpoint=
?redirect=
?src=
?source=
?feed=
?host=
?target=
?dest=
?file=
?path=
?callback=
?image=
?load=
?fetch=JS Patterns (in client-side code)
// Look for these in JS bundles
fetch(userInput)
axios.get(params.url)
XMLHttpRequest + variable URL
url: req.body.url
src: params.source
href: query.endpointResponse Header Signals
X-Forwarded-For headers echoed back
Server: internal-service
Via: 1.1 internal-proxy
X-Cache headers revealing internal hostnamesTech Stack Signals
- Kubernetes — any public-facing aggregated API, metrics endpoints
- GCP — any service fetching URLs that runs on Compute Engine/GKE
- Node.js/Python with URL-fetching libraries (
requests,node-fetch,axios) - Headless browsers (Puppeteer, PhantomJS) used for screenshots/PDF — extremely high value
- XML/DSPL/CSV import features — XXE-style SSRF vector
- OAuth/webhook registration endpoints
---
Step-by-Step Hunting Methodology
1. Map all URL-input parameters across the target: spider JS files for fetch calls, check all API docs, look for file-import, link-preview, webhook, image-proxy, and redirect features.
2. Set up an out-of-band detection server using Burp Collaborator, interactsh, or https://canarytokens.org — you need a unique per-test DNS/HTTP callback domain.
3. Send your callback URL as the parameter value first (blind SSRF check before anything else):
url=https://YOUR.interactsh.com/test
Confirm the server makes an outbound connection. This proves execution
… (full content is in the download package)
Related skills
- hunt-subdomain – Hunting skill for subdomain takeover vulnerabilities.
- hunt-websocket – Hunt WebSocket vulnerabilities
- hunt-xss – Hunting skill for xss vulnerabilities.
- hunt-xxe – Hunting skill for xxe vulnerabilities.
- incident-response – Handle security incidents with IR playbooks and procedures.
- iso27001-compliance – Implement ISO 27001 Information Security Management System. Configure ISMS controls and…
- tech-stack-evaluator – Technology stack evaluation and comparison with TCO analysis, security assessment, and…
- threat-detection – Use when hunting for threats in an environment, analyzing IOCs, or detecting behavioral…