ssrfsink_prescan report — 6 file(s), 11 finding(s)

HIGH   SF-REQ-SINK        sample-repo/go/probe.go:5  request-derived 'u' (line 4) into an outbound fetch
       | http.Get(u)
HIGH   SF-REQ-SINK        sample-repo/js/feed.js:5  request-derived 'feed_url' (line 4) into an outbound fetch
       | const data = await axios.get(feed_url);
HIGH   SF-REQ-SINK        sample-repo/js/feed.js:12  request-derived 'u' (line 10) into an outbound fetch
       | return res.send(await fetch(u).then(r => r.text()));
HIGH   SF-SCHEME-SINK     sample-repo/php/img.php:3  request-derived 'u' (line 2) into an outbound fetch (multi-scheme sink)
       | $img = file_get_contents($u);
HIGH   SF-SCHEME-SINK     sample-repo/php/img.php:5  request-derived value into an outbound fetch (multi-scheme sink: file:// / gopher:// wrappers apply)
       | curl_setopt($ch, CURLOPT_URL, $_GET['u']);
HIGH   SF-REQ-SINK        sample-repo/py/webhook.py:13  request-derived 'u' (line 12) into an outbound fetch; redirects followed — first-hop checks do not re-validate
       | return requests.get(u, allow_redirects=True).text
HIGH   SF-SCHEME-SINK     sample-repo/rb/open.rb:2  request-derived 'u' (line 1) into an outbound fetch (multi-scheme sink)
       | doc = URI.open(u).read
MEDIUM SF-SUBSTR-GUARD    sample-repo/js/feed.js:11  URL guard is a substring/prefix-domain test — bypassable (api.example.com.evil.tld, evilapi.example.com); compare the parsed hostname against an exact allowlist
       | if (u.includes("api.example.com")) {
LOW    SF-URL-PARAM       sample-repo/py/webhook.py:6  request value stored in url-named 'webhook_url' — blind-SSRF surface if any path later fetches it; enforce an allowlist at the fetch site
       | webhook_url = request.json.get("callback_url")
LOW    SF-DECODE-FETCH    sample-repo/py/webhook.py:19  'u' is decode output (line 18) — validation on the encoded form is bypassed; decode THEN validate
       | return requests.get(u).content
LOW    SF-DNS-THEN-FETCH  sample-repo/py/webhook.py:24  hostname 'host' resolved/checked at line 22 then connected BY NAME here — DNS-rebinding TOCTOU; connect to the checked IP or pin at connect time
       | return requests.get("http://" + host + "/health")

scope: deterministic pre-scan — flags SSRF dataflow shapes for review; not an audit, clean != SSRF-free
