T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/image_create.py:530
- Finding
- API credentials and article content can be transmitted over plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/image_create.py`, lines 530–607 **Vulnerability Type**: Authenticated requests over an unrestricted URL scheme **Risk Level**: High ### Vulnerable Code ```python b = model_cfg["base_url"].rstrip("/") bl = b.lower() if api_type == "volcengine": url = b if "/api/v3/images/generations" in bl else f"{b}/api/v3/images/generations" elif api_type == "openai": if "/v1/chat/completions" in bl: url = b elif "/v1/images/generations" in bl: url = b else: _err( "image_model.base_url must contain the complete endpoint path." ) use_chat = "/v1/chat/completions" in url.lower() sent_aspect = None if use_chat: if aspect and _supports_image_config(model_cfg): sent_aspect = _nearest_supported_aspect(aspect) body = { "model": model_cfg["model"], "messages": [{"role": "user", "content": prompt}], } else: body = { "model": model_cfg["model"], "prompt": prompt, "n": 1, "size": size or model_cfg["default_size"], "quality": quality or model_cfg["default_quality"], "response_format": "b64_json", } data = json.dumps(body, ensure_ascii=False).encode("utf-8") req = urllib.request.Request( url, data=data, headers={ "Content-Type": "application/json", "Authorization": f"Bearer {model_cfg['api_key']}", }, ) try: with urllib.request.urlopen(req, timeout=120) as resp: result = json.loads(resp.read()) except urllib.error.HTTPError as e: error_body = e.read().decode("utf-8", errors="replace") _err(_format_api_failure("API call failed", e.code, error_body)) except (urllib.error.URLError, TimeoutError) as e: _fail_url(e, "connecting to image-generation API") ``` The same underlying issue also affects authenticated request construction for Gemini and Qwen endpoints around lines 628–662 and 696–730. ### Technical Analysis The co ...[truncated 1991 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse every API endpoint before constructing an authenticated request: ```python parsed = urllib.parse.urlparse(url) if parsed.scheme != "https": _err("Remote image-model endpoints must use HTTPS") ``` 2. If local development endpoints are necessary, permit plaintext HTTP only through an explicit opt-in and only for loopback addresses: ```python allow_local_http = config.get("allow_local_http", False) if parsed.scheme == "http": if not allow_local_http or parsed.hostname not in {"127.0.0.1", "::1", "localhost"}: _err("Plaintext HTTP is not permitted") ``` 3. Apply the same validation consistently to OpenAI-compatible, Volcengine, Gemini, Qwen, and asynchronous polling URLs. 4. Reject URLs containing embedded user information, malformed hosts, or unsupported schemes. 5. Recommend provider-specific, narrowly scoped API keys with independent quotas and billing limits. 6. Document that remote endpoints must use valid TLS and that users should not disable certificate verification. ]]>
