T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/create_and_wait.py:63
- Finding
- API Key Disclosure Through Unrestricted Credential-Bearing Request Destinations<![CDATA[ ## Vulnerability Details **File Location**: `scripts/create_and_wait.py:63-68, 156-170, 221, 324-325, 354-363`; `scripts/wait_generation.py:79-100, 107, 154-159` **Vulnerability Type**: Unrestricted transmission of bearer credentials to user-controlled URLs **Risk Level**: High ### Vulnerable Code `scripts/create_and_wait.py:63-68`: ```python def endpoint_url(base_url: str, endpoint: str) -> str: if endpoint.startswith("http://") or endpoint.startswith("https://"): return endpoint if not endpoint.startswith("/"): endpoint = "/" + endpoint return f"{base_url.rstrip('/')}{endpoint}" ``` `scripts/create_and_wait.py:156-170`: ```python def run_sse( url: str, api_key: str, payload: dict[str, Any], request_timeout: float, ) -> tuple[int, str | None, Any]: req = request.Request( url, headers={ "Authorization": f"Bearer {api_key}", "Accept": "text/event-stream", "Content-Type": "application/json", }, data=json.dumps(payload).encode("utf-8"), method="POST", ) ``` `scripts/create_and_wait.py:324-325, 354-363`: ```python parser.add_argument("--sse-endpoint", required=True, help="SSE create endpoint path or full URL") parser.add_argument("--base-url", default="https://open.skills.video/api/v1") ``` ```python payload = load_payload(args) url = endpoint_url(args.base_url, args.sse_endpoint) emit({"event": "start", "url": url, "mode": "sse_then_poll_fallback"}) sse_rc, generation_id, terminal_payload = run_sse( url=url, api_key=api_key, payload=payload, request_timeout=args.sse_request_timeout, ) ``` `scripts/wait_generation.py:79-100`: ```python def fetch_generation( base_url: str, generation_id: str, api_key: str, request_timeout: float, ) -> tuple[int, Any]: url = f"{base_url.rstrip('/')}/generation/{generation_id}" req = request.Request( url, headers={ "Aut ...[truncated 3396 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Reject absolute values for `--sse-endpoint`; accept only relative API paths. 2. Parse all destinations with `urllib.parse.urlsplit` and enforce: - Scheme exactly `https`. - Hostname exactly `open.skills.video`. - No URL user information. - Only the expected HTTPS port. 3. Apply the same validation to `--base-url` in both scripts. 4. Prefer removing destination overrides entirely unless model-specific OpenAPI contracts demonstrably require them. 5. If overrides are required, use an explicit allowlist rather than suffix or substring checks. 6. Prevent authenticated requests from following redirects to a different origin, or revalidate every redirect target and strip authorization on any origin change. 7. Add tests confirming rejection of: - `http://open.skills.video/...` - `https://attacker.example/...` - `https://open.skills.video.attacker.example/...` - `https://attacker.example@open.skills.video/...` - Cross-origin redirects. 8. Use a narrowly scoped API key where the platform supports key-level permissions and rotation. ]]>
