T09 · Insecure Skill Coding Practices
- Location
scripts/sec_headers.py:140- Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery and Resource Exhaustion
- Content
View full analysis
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: HighVulnerable 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
- 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.
- The scheme check accepts the HTTP or HTTPS URL and passes it to
audit_url(). ...[truncated 1449 chars]
- Remediation
View remediation
Remediation Suggestions
- Parse URLs with a standards-compliant parser and permit only explicitly required schemes, normally HTTPS.
- Reject URLs containing embedded credentials or ambiguous host syntax.
- Resolve the hostname before connecting and reject all loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 addresses.
- Protect against DNS rebinding by ensuring the validated address is the address actually used for the connection.
- Disable automatic redirects and process redirects manually. Resolve and validate every redirect destination before following it, and enforce a low redirect limit.
- Prefer an explicit hostname or network allowlist where the deployment permits one.
- 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()}- Enforce connection and read timeouts, a total operation deadline, and limits on response headers and redirects.
- Run the Skill in a network sandbox that cannot reach cloud metadata endpoints, loopback services, management networks, or unrelated internal systems.
