T05 · Unauthorized Access and Privilege Escalation
- Location
- scan_uis.py:63
- Finding
- HTTP redirects can escape the declared loopback-only probing boundary<![CDATA[ ## Vulnerability Details **File Location**: `scan_uis.py:63-82` **Vulnerability Type**: Server-side request forgery through unrestricted redirects **Risk Level**: High ### Vulnerable Code ```python def probe(port): """Return dict if the port speaks HTTP, else None.""" url = f"http://127.0.0.1:{port}/" req = urllib.request.Request(url, headers={"User-Agent": "local-uis-scan"}) try: with urllib.request.urlopen(req, timeout=1.4) as r: status = r.status ctype = r.headers.get("Content-Type", "") body = b"" if "html" in ctype.lower() or ctype == "": body = r.read(8192) title = "" mt = re.search(rb"<title[^>]*>(.*?)</title>", body, re.I | re.S) if mt: title = html.unescape(mt.group(1).decode("utf-8", "ignore")).strip()[:90] return {"port": port, "status": status, "ctype": ctype.split(";")[0], "title": title} except urllib.error.HTTPError as e: # 401/403/404 etc still means something is serving here return {"port": port, "status": e.code, "ctype": "", "title": ""} ``` This conflicts with the safety statement in `SKILL.md:26-27`: ```markdown - The tool does not probe other hosts or non-loopback addresses. - A service bound to all interfaces may still be externally reachable; this scanner does not establish network isolation. ``` ### Technical Analysis The initial URL uses `127.0.0.1`, but `urllib.request.urlopen()` follows HTTP redirects by default. The code neither disables redirects nor validates each redirect destination. A process controlling a discovered loopback listener can return a redirect to an arbitrary URL, including: - An internal network service - A link-local service - A cloud metadata-style endpoint - An Internet host - Another service reachable using the invoking user's network permissions The resulting request is no longer constrained to loopback. The standard URL opener may also use ...[truncated 1556 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Disable automatic redirect handling for scanner requests. 2. If redirects are required, validate every redirect hop rather than only the initial URL. 3. Permit only `http` URLs whose resolved destination is a loopback address. 4. Reject user-info components, non-HTTP schemes, malformed hosts, and redirect chains exceeding a small fixed limit. 5. Resolve hostnames and verify every returned address with `ipaddress.ip_address(address).is_loopback`. 6. Use a proxy-free opener so environment proxy variables cannot change request routing. 7. Add automated tests for redirects to: - Public Internet hosts - RFC 1918 private addresses - Link-local addresses - IPv4 and IPv6 loopback addresses - Hostnames resolving to non-loopback addresses - Multi-hop redirect chains 8. Update `SKILL.md` so its safety claim accurately reflects the enforced behavior. A restrictive implementation should fail closed whenever a redirect target cannot be conclusively validated as loopback. ]]>
