T09 · Insecure Skill Coding Practices
- Location
scripts/reddapi.py:24- Finding
Environment-controlled API endpoint can redirect bearer credentials
- Content
View full analysis
dict: """Send one request and return the decoded JSON body. POST bodies always carry Content-Type: application/json; without it the server answers 403 ("Cross-site POST form submissions are forbidden"), which is a header problem and not a plan limit. """ url = f"{BASE_URL}{path}" if params: clean = {k: v for k, v in params.items() if v is not None} if clean: url = f"{url}?{urllib.parse.urlencode(clean)}" headers = {"Accept": "application/json"} if auth: headers["Authorization"] = f"Bearer {_api_key()}" ``` ### Technical Analysis The authenticated client obtains its destination from the unrestricted `REDDAPI_BASE_URL` environment variable. The value is neither constrained to the declared `reddapi.dev` service nor required to use HTTPS. For authenticated operations, the same request function unconditionally adds `REDDAPI_API_KEY` as a bearer token. Consequently, any party that can influence the process environment or launch configuration can select the server that receives the credential. The endpoint override is not required by the Skill's documented Reddit-search functionality and expands credential exposure beyond the minimum privilege boundary. Existing tests verify that the key is absent from the request URL and body, but they do not verify that the Authorization header is sent exclusively to the trusted provider. ### Attack Path 1. An attacker gains influence over the environment or configuration used to launch the Skill. 2. The attacker sets `REDDAPI_B ...[truncated 1303 chars]- Remediation
View remediation
bool: parsed = urlsplit(url) return ( parsed.scheme == "https" and parsed.hostname == TRUSTED_HOST and parsed.port in (None, 443) and parsed.username is None and parsed.password is None ) if auth: if not _is_trusted_api_url(url): raise ApiError("refusing to send credentials to an untrusted endpoint") headers["Authorization"] = f"Bearer {_api_key()}" ``` 5. Add tests confirming that authenticated requests reject: - Plain HTTP destinations. - Unapproved domains and subdomains. - URLs containing user information. - Hostname-confusion values such as `reddapi.dev.attacker.example`. - Unexpected ports. - Any overridden endpoint when a production bearer key would be attached. 6. Preserve the existing safeguards that keep the key out of URLs, request bodies, logs, and error messages. ]]>
