T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/sec_headers.py:140
- Finding
- Unrestricted URL Fetching Enables Server-Side Request Forgery and Resource Exhaustion## Vulnerability Details **File Location**: `scripts/sec_headers.py`, lines 140 and 265–268 **Vulnerability Type**: Server-Side Request Forgery and uncontrolled response buffering **Risk Level**: High ### Vulnerable Code ```python resp = requests.get(url, headers=headers, timeout=timeout, allow_redirects=True) ``` The untrusted URL reaches this request through the following code: ```python results = [] for url in args.urls: if not url.startswith(("http://", "https://")): url = "https://" + url results.append(audit_url(url, args.timeout)) ``` ### Technical Analysis The command-line URL is passed directly to `requests.get()` without validating the destination host or its resolved IP addresses. The scheme check only verifies that the URL begins with HTTP or HTTPS; it does not prevent access to loopback, private, link-local, reserved, multicast, or otherwise internal addresses. Automatic redirects are enabled with `allow_redirects=True`. Even if validation of the initial URL were added, an attacker-controlled public endpoint could redirect the request to an internal destination unless every redirect target is independently resolved and validated. DNS rebinding may similarly cause a previously acceptable hostname to resolve to a prohibited address when the connection is made. The request is also made without `stream=True`. The Requests library therefore downloads and buffers the response body before returning, even though the application only uses the response status and headers. A remote server can return a very large or continuously generated body to consume process memory. The timeout is not a total download deadline and does not by itself establish a maximum response size. ### Attack Path 1. An attacker supplies a URL targeting a loopback address, private network host, cloud metadata service, or another service reachable from the machine running the Skill. 2. The scheme check accepts the HTTP or HTTPS URL and passes it to `audit_url()`. ...[truncated 1449 chars]
- Remediation
- ## Remediation Suggestions 1. Parse URLs with a standards-compliant parser and permit only explicitly required schemes, normally HTTPS. 2. Reject URLs containing embedded credentials or ambiguous host syntax. 3. Resolve the hostname before connecting and reject all loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 addresses. 4. Protect against DNS rebinding by ensuring the validated address is the address actually used for the connection. 5. Disable automatic redirects and process redirects manually. Resolve and validate every redirect destination before following it, and enforce a low redirect limit. 6. Prefer an explicit hostname or network allowlist where the deployment permits one. 7. Use a streaming request and close it without consuming the body: ```python with requests.get( url, headers=headers, timeout=(3, timeout), allow_redirects=False, stream=True, ) as resp: result["status"] = resp.status_code resp_headers = {k.lower(): v for k, v in resp.headers.items()} ``` 8. Enforce connection and read timeouts, a total operation deadline, and limits on response headers and redirects. 9. Run the Skill in a network sandbox that cannot reach cloud metadata endpoints, loopback services, management networks, or unrelated internal systems.
