T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/convert-to-pdf.py:46
- Finding
- Unrestricted Base URL Override Can Disclose Documents and API Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/convert-to-pdf.py`, lines 46-62, 77-84, and 213-216 **Vulnerability Type**: Unvalidated destination for sensitive network transfers **Risk Level**: High ### Vulnerable Code ```python def create_job( base_url: str, api_key: str, file_paths: List[str], timeout_s: int = 180, ) -> Dict[str, Any]: url = base_url.rstrip("/") + CREATE_PATH headers = make_headers(api_key) # multipart/form-data with multiple files under the SAME key: "files" files: List[Tuple[str, Tuple[str, Any, str]]] = [] opened = [] # We don't enforce input mime types; use octet-stream for broad compatibility. try: for p in file_paths: f = open(p, "rb") opened.append(f) files.append(("files", (os.path.basename(p), f, "application/octet-stream"))) resp = requests.post(url, headers=headers, files=files, timeout=timeout_s) ``` ```python def get_job( base_url: str, api_key: str, job_id: Any, timeout_s: int = 30, ) -> Dict[str, Any]: url = base_url.rstrip("/") + f"/api/{job_id}" headers = make_headers(api_key) resp = requests.get(url, headers=headers, timeout=timeout_s) ``` ```python ap.add_argument( "--base-url", default=os.getenv("SOLUTIONS_BASE_URL", DEFAULT_BASE_URL), help="Base URL override", ) ``` ### Technical Analysis The conversion workflow legitimately requires transmitting selected documents and a Bearer API key to the documented Solutions API. However, the destination is configurable through both the `--base-url` command-line argument and the `SOLUTIONS_BASE_URL` environment variable. The supplied URL is used without validation of its scheme, hostname, port, or relationship to the expected API domain. Consequently, it may reference: - An attacker-controlled HTTPS server. - A plaintext HTTP endpoint, exposing data to network interception. - An unexpected internal service reachable from ...[truncated 2436 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove arbitrary endpoint overrides where possible** - Always use the documented `DEFAULT_BASE_URL` in production. - Remove `--base-url` and `SOLUTIONS_BASE_URL` if alternate deployments are not a strict operational requirement. 2. **Apply a destination allowlist** - Parse the URL with `urllib.parse.urlsplit()`. - Require the normalized hostname to equal an explicitly approved API hostname. - Do not use suffix-only checks such as `hostname.endswith("trusted.example")` unless subdomains are intentionally trusted. - Reject URLs containing user information, fragments, or unexpected ports. 3. **Enforce transport security** - Require the `https` scheme. - Reject plaintext HTTP even for configurable development endpoints. - Retain TLS certificate verification and do not introduce `verify=False`. 4. **Separate credentials by destination** - Never forward the production Solutions API key to an alternate endpoint. - If alternate endpoints are required, provision separate least-privilege credentials for each approved host. 5. **Require explicit approval for non-default destinations** - Display the normalized destination before any document or credential is transmitted. - Require an explicit user confirmation when the destination differs from the official service. - Clearly disclose that selected documents are uploaded to a third party. 6. **Minimize token exposure** - Prefer environment-based secret input over `--api-key`, because command-line arguments may be visible in process listings or shell history. - Use narrowly scoped and short-lived API tokens where supported. - Continue avoiding credential values in logs and error messages. 7. **Add security tests** - Verify that HTTP URLs, attacker-controlled domains, embedded credentials, malformed URLs, and unauthorized ports are rejected. - Verify that no network request occurs before destination validation succeeds. ]]>
