T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/openmandate.py:37
- Finding
- Unvalidated API Base URL Can Disclose the OpenMandate Bearer Credential<![CDATA[ ## Vulnerability Details **File Location**: `scripts/openmandate.py`, lines 37–62 **Vulnerability Type**: Unvalidated credential destination / sensitive credential disclosure **Risk Level**: High ### Vulnerable Code ```python def _get_base_url() -> str: return os.environ.get(BASE_URL_ENV, DEFAULT_BASE_URL).rstrip("/") def _die(message: str) -> None: print(f"Error: {message}", file=sys.stderr) sys.exit(1) def _request(method: str, path: str, params: dict | None = None) -> dict: """Make an HTTP request to the OpenMandate API and return parsed JSON.""" base = _get_base_url() url = f"{base}{path}" if params: query = urllib.parse.urlencode({key: value for key, value in params.items() if value is not None}) if query: url = f"{url}?{query}" req = urllib.request.Request(url, method=method) req.add_header("Authorization", f"Bearer {_get_api_key()}") req.add_header("Content-Type", "application/json") req.add_header("Accept", "application/json") req.add_header("User-Agent", USER_AGENT) ``` ### Technical Analysis The helper obtains the request origin directly from the configurable `OPENMANDATE_BASE_URL` environment variable. It does not validate the URL scheme, hostname, port, path, or user-information component before attaching the secret from `OPENMANDATE_API_KEY` as a bearer credential. Consequently, the authorization header is not restricted to the legitimate `https://api.openmandate.ai` origin. A manipulated configuration can direct an authenticated request to an attacker-controlled HTTP or HTTPS endpoint. Allowing plain HTTP also permits interception of the credential by a network-positioned attacker. The HTTP client additionally relies on default redirect handling without explicitly enforcing a same-origin redirect policy. Security-sensitive authorization headers should never be forwarded to a different origin during redirects. ### Attack Path 1. An attacker obtains th ...[truncated 1653 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove `OPENMANDATE_BASE_URL` support from production builds if endpoint customization is unnecessary. 2. Otherwise, parse the configured URL with `urllib.parse.urlsplit()` and enforce all of the following: - The scheme must be `https`. - The normalized hostname must exactly match an explicit allowlist, preferably only `api.openmandate.ai`. - The port must be absent or explicitly approved. - User information, fragments, query strings, and unexpected base paths must be rejected. 3. Construct API URLs from validated components rather than concatenating an arbitrary string with a path. 4. Implement an explicit redirect policy that either disables redirects or permits only same-scheme, same-host, and same-port redirects. 5. Ensure the `Authorization` header is removed before following any cross-origin redirect. 6. Do not send credentials over plain HTTP, including in development environments. 7. Add automated tests covering malicious schemes, lookalike domains, embedded credentials, unexpected ports, path confusion, and cross-origin redirects. 8. Rotate the API key if the helper has previously run with an untrusted `OPENMANDATE_BASE_URL`. ]]>
