T09 · Insecure Skill Coding Practices
Error
- Location
- examples.py:11
- Finding
- Bearer Token Disclosure Through an Unrestricted Relay URL Override<![CDATA[ ## Vulnerability Details **File Location**: `examples.py`, lines 11–13 **Vulnerability Type**: Credential disclosure through an unvalidated network destination **Risk Level**: High ### Vulnerable Code ```python RELAY = os.environ.get("SYNAI_RELAY_URL", "https://synai-relay.ondigitalocean.app") KEY = os.environ["SYNAI_API_KEY"] HEADERS = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"} ``` The resulting `HEADERS` object is subsequently attached to authenticated requests made to URLs derived from `RELAY`, for example: ```python task = requests.post(f"{RELAY}/jobs", headers=HEADERS, json={ "title": "Write a Python CLI tool", "description": "Build a CLI tool that converts CSV to JSON with filtering support.", "rubric": "1. Accepts CSV input via stdin or file arg\n" "2. Outputs valid JSON\n" "3. Supports --filter flag for column filtering\n" "4. Includes --help with usage examples", "price": "2.00", "expiry_hours": 48, "max_submissions": 10, "max_retries": 3, "artifact_type": "CODE", }).json() ``` ### Technical Analysis The relay destination is read directly from the environment without validating its scheme, hostname, port, or origin. At the same time, the API key is unconditionally inserted into the `Authorization` header for authenticated requests. As a result, setting `SYNAI_RELAY_URL` to an attacker-controlled URL causes the client to transmit `SYNAI_API_KEY` to that server. The configuration also permits a plaintext `http://` destination, exposing the bearer token to interception or modification by an on-path attacker. Allowing a configurable service endpoint can be legitimate for testing or self-hosting, but automatically forwarding a production bearer credential to any configured origin is not a least-privilege design. The destination should be authenticated or explicitly trusted before credentials are attached. ### Attack Path 1. An attacker in ...[truncated 1503 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Default to the official relay origin and enforce HTTPS: ```python from urllib.parse import urlparse import os OFFICIAL_RELAY = "https://synai-relay.ondigitalocean.app" RELAY = os.environ.get("SYNAI_RELAY_URL", OFFICIAL_RELAY).rstrip("/") parsed = urlparse(RELAY) if parsed.scheme != "https": raise ValueError("SYNAI_RELAY_URL must use HTTPS") if parsed.username or parsed.password or parsed.fragment: raise ValueError("SYNAI_RELAY_URL contains prohibited URL components") ``` 2. Allowlist the official hostname for normal operation. If self-hosted endpoints are supported, require an explicit security-sensitive opt-in rather than trusting any environment value implicitly. 3. Bind credentials to a trusted origin. Construct the authorization header only after validating the destination: ```python ALLOWED_HOSTS = {"synai-relay.ondigitalocean.app"} if parsed.hostname not in ALLOWED_HOSTS: raise ValueError("Refusing to send SYNAI_API_KEY to an untrusted host") headers = { "Authorization": f"Bearer {KEY}", "Content-Type": "application/json", } ``` 4. If alternate relays are a required feature, use separate credentials for each relay and never reuse the production API key across origins. 5. Reject unexpected ports, URL user information, fragments, and non-HTTPS schemes. Consider certificate pinning or an equivalent trust policy for high-value deployments. 6. Document that `SYNAI_RELAY_URL` is security-sensitive and must not be populated from untrusted task content or externally supplied agent instructions. 7. Rotate any API key that may already have been sent to an untrusted destination and review relay activity for unauthorized operations. ]]>
