T09 · Insecure Skill Coding Practices
- Location
scripts/public_api.py:12- Finding
Unrestricted API Base URL Enables Server-Side Request Forgery
- Content
View full analysis
EnvConfig: """Resolve final base URL from env / override.""" if base_url: return EnvConfig(base_url=base_url.rstrip("/")) ``` ```python def http_get_json(url: str) -> Dict[str, Any]: """Perform a GET request and return parsed JSON.""" req = request.Request(url, method="GET") req.add_header("Content-Type", "application/json") try: with request.urlopen(req, timeout=15) as resp: status = resp.getcode() body = resp.read().decode("utf-8") ``` ```python parser.add_argument( "--base-url", help="Optional: custom API root URL; takes precedence when set.", ) ``` ### Technical Analysis The `--base-url` argument accepts an arbitrary URL and gives it precedence over the two documented Stove API environments. No validation restricts the URL scheme, hostname, port, resolved IP address, or redirect destination. The resulting value is combined with an API path and passed to `urllib.request.urlopen`. Python's standard URL opener follows HTTP redirects by default. Consequently, a caller can direct the skill to an attacker-controlled endpoint, a loopback service, a private-network host, or a link-local service. An attacker-controlled server can also redirect the request to a destination that could not conveniently be addressed using the appended Stove API path. The implementation does not enforce HTTPS and does not reject loopback, private, link-local, multicast, or reserved IP ranges. It also does not revalidate redirect targets. These behaviors violate least-destination principles for a skill whose documented network activity only requires access to two fixed Stove API hosts. The ticker ...[truncated 2382 chars]- Remediation
View remediation
