T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/ratsinfo.py:205
- Finding
- Cross-Host Restriction Bypass Through Automatic HTTP Redirects<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ratsinfo.py:69-75, 149-155, 205-216` **Vulnerability Type**: Server-Side Request Forgery through redirects **Risk Level**: High ### Vulnerable Code The shared opener enables automatic redirects: ```python _OPENER = urllib.request.build_opener( urllib.request.HTTPHandler, urllib.request.HTTPSHandler, urllib.request.HTTPRedirectHandler, urllib.request.HTTPErrorProcessor, ) ``` The main JSON-fetching path validates the final host only after the redirect-capable opener has completed the request: ```python req = urllib.request.Request( url, headers={ "User-Agent": USER_AGENT, "Accept": "application/json, */*;q=0.5", }, method="GET", ) with _OPENER.open(req, timeout=TIMEOUT) as resp: final = resp.geturl() if _host(final) != _host(url): _check_url(final) # a redirect off host needs consent too raw = resp.read(MAX_BYTES + 1) ``` The `robots.txt` path uses the same opener and does not validate its final URL: ```python req = urllib.request.Request( robots_url, headers={"User-Agent": USER_AGENT} ) with _OPENER.open(req, timeout=TIMEOUT) as resp: body = resp.read(1024 * 1024).decode("utf-8", "replace") parser.parse(body.splitlines()) ``` ### Technical Analysis The Skill attempts to restrict requests to the host explicitly selected by the user. However, `urllib.request.HTTPRedirectHandler` follows HTTP redirects inside `_OPENER.open()` before control returns to the caller. Consequently, when this code evaluates `resp.geturl()` and invokes `_check_url(final)`, the redirected request has already been transmitted. The check can prevent processing of the response, but it cannot prevent the cross-host network interaction. The `robots.txt` request is more exposed because it uses the same redirect-capable opener without performing any final-host validation. Only URL schemes are restricted. The implementation does not reject loopbac ...[truncated 1852 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace the permissive redirect handler with a custom handler that validates every redirect target before following it. 2. Call `_check_url()` from `redirect_request()` or an equivalent pre-request interception point, rather than checking only after `_OPENER.open()` returns. 3. Use the same validated redirect policy for both OParl requests and `robots.txt`. 4. Reject loopback, private, link-local, multicast, unspecified, and reserved IP destinations by default. 5. Resolve hostnames and validate all returned addresses before connecting. Revalidate the connected destination where practical to reduce DNS rebinding exposure. 6. Consider disabling redirects by default and handling each redirect explicitly with a small maximum redirect count. 7. Permit cross-host redirects only when `--allow-cross-host` is explicitly provided. 8. Add regression tests proving that an off-host redirect does not cause any connection to the target server. 9. Add separate tests for endpoint, pagination, object-dereference, and `robots.txt` redirects. 10. Update the documentation only after the restriction is enforced before network transmission. ]]>
