T09 · Insecure Skill Coding Practices
- Location
scripts/illustrate.py:33- Finding
API Credential and Prompt Disclosure Through an Unvalidated Configurable Endpoint
- Content
View full analysis
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
View remediation
