T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/illustrate.py:33
- Finding
- API Credential and Prompt Disclosure Through an Unvalidated Configurable Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/illustrate.py`, lines 33–41 and 171–181 **Vulnerability Type**: Unvalidated network destination for sensitive credentials **Risk Level**: High ### Vulnerable Code ```python def _api_url() -> str: base = ( os.environ.get("OPENAI_BASE_URL") or os.environ.get("OPENAI_API_BASE") or "https://api.openai.com" ).rstrip("/") if base.endswith("/v1"): return f"{base}/images/generations" return f"{base}/v1/images/generations" ``` ```python def _post_json(url: str, api_key: str, payload: dict, timeout_s: int) -> dict: body = json.dumps(payload).encode("utf-8") req = urllib.request.Request( url, data=body, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", }, method="POST", ) try: with urllib.request.urlopen(req, timeout=timeout_s) as resp: raw = resp.read() ``` The sensitive request is made at lines 342–358: ```python url = _api_url() items: list[dict] = [] for i, (prompt, metadata) in enumerate(prompts_with_meta, 1): print(f"Generating illustration {i}/{len(prompts_with_meta)}...") payload = { "model": args.model, "prompt": prompt, "size": args.size, "quality": args.quality, "n": 1, "response_format": "b64_json", } data = _post_json(url=url, api_key=api_key, payload=payload, timeout_s=args.timeout) ``` ### Technical Analysis The Skill legitimately needs to send a prompt and API credential to the OpenAI Images API. However, `_api_url()` accepts `OPENAI_BASE_URL` and `OPENAI_API_BASE` directly from the process environment without validating: - The destination hostname - Whether the URL uses HTTPS - Whether the URL contains embedded credentials or an unusual port - Whether the destination is an approved OpenAI or explicitly trusted proxy endpoint The selected U ...[truncated 1948 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Restrict the default destination to `https://api.openai.com`. 2. Parse configured URLs with `urllib.parse.urlsplit()` and reject: - Non-HTTPS schemes - Missing or unexpected hostnames - Embedded usernames or passwords - Unapproved ports - URL fragments 3. Maintain an explicit allowlist of approved API hostnames. 4. If custom proxies are required, require an explicit command-line option and informed user confirmation rather than silently trusting inherited environment variables. 5. Document that a custom endpoint receives both the API credential and complete prompt. 6. Use a separate proxy-specific credential when connecting to a third-party gateway instead of automatically forwarding the OpenAI API key. 7. Disable or validate cross-origin redirects for authenticated requests so credentials cannot be forwarded to a different host. 8. Reject plaintext HTTP endpoints under all normal operating modes. ]]>
