T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:258
- Finding
- Unrestricted Remote Specification Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 258–266 **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unrestricted outbound network access **Risk Level**: High ### Vulnerable Code ```python if source.startswith("http://") or source.startswith("https://"): try: import urllib.request with urllib.request.urlopen(source, timeout=10) as r: content = r.read().decode() except Exception as e: sys.exit(f"Cannot fetch spec from URL: {e}") ``` ### Technical Analysis The scanner accepts an arbitrary user-controlled HTTP or HTTPS URL and passes it directly to `urllib.request.urlopen`. It does not validate the destination hostname, resolved IP address, port, URL credentials, or redirect target. Although fetching public OpenAPI specifications is part of the declared functionality, unrestricted access to arbitrary network locations exceeds the minimum privileges necessary. The implementation does not: - Require HTTPS. - Restrict requests to public Internet addresses. - Block loopback, private, link-local, reserved, or cloud metadata addresses. - Revalidate destinations after DNS resolution or HTTP redirects. - Restrict destination ports. - Impose a maximum response-body size. - Reject URLs containing embedded credentials or sensitive query parameters. The ten-second timeout limits request duration but does not prevent SSRF or memory exhaustion from a large response delivered within that period. Because redirects are followed by the standard URL handler, an initially public URL may redirect to an internal address. ### Attack Path 1. An attacker supplies a scanner input such as a loopback URL, private-network URL, cloud metadata URL, or attacker-controlled public redirect. 2. The Skill invokes `load_spec` with that URL. 3. `urllib.request.urlopen` connects from the agent's execution environment without destination validation. 4. The request reaches services that may be inaccessible to th ...[truncated 1361 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Make local-file scanning the default and require an explicit option such as `--allow-remote` before enabling network access. 2. Permit only HTTPS unless the user explicitly authorizes an exceptional development use case. 3. Parse URLs with `urllib.parse.urlsplit` and reject: - Embedded usernames or passwords. - Unsupported schemes. - Empty or malformed hostnames. - Unexpected destination ports. 4. Resolve the hostname before connecting and reject every address classified by `ipaddress` as loopback, private, link-local, multicast, reserved, or unspecified. 5. Explicitly block known metadata destinations, including `169.254.169.254` and equivalent IPv6 addresses. 6. Disable automatic redirects or validate the scheme, hostname, resolved addresses, and port after every redirect. 7. Protect against DNS rebinding by connecting only to the validated resolved address while preserving safe TLS hostname verification. 8. Use an allowlist when remote sources are expected to come from known registries or domains. 9. Stream the response in bounded chunks and enforce a conservative maximum size before parsing it. 10. Set connection and read timeouts and limit the number of redirects. 11. Avoid printing complete URLs when they may contain sensitive query parameters; redact credentials and token-like values. 12. Run remote fetching in a sandbox with restricted egress and no access to metadata endpoints or internal networks. ]]>
