T09 · Insecure Skill Coding Practices
Warning
- Location
- skill.py:481
- Finding
- Configurable Local Endpoint Bypasses Remote Image Upload Safeguards<![CDATA[ ## Vulnerability Details **File Location**: `skill.py`, lines 481-567 and 634-659 **Vulnerability Type**: Remote data disclosure caused by trust-label-based endpoint classification **Risk Level**: Medium ### Vulnerable Code ```python class VLClient: def __init__(self, endpoint: str, model: str, api_key: str = "", max_tokens: int = 2048, timeout: int = 120, is_remote: bool = False, require_confirm: bool = True): self.endpoint = endpoint.rstrip("/") self.model = model self.api_key = api_key self.max_tokens = max_tokens self.timeout = timeout self.is_remote = is_remote self.require_confirm = require_confirm self.confirmed = False self.headers = {"Content-Type": "application/json"} if api_key: self.headers["Authorization"] = f"Bearer {api_key}" def analyze_image(self, image_path: str, prompt: str) -> dict: if self.is_remote and self.require_confirm and not self.confirmed: if not sys.stdin.isatty(): raise PermissionError( "Remote transmission requires confirmation." ) confirm = input("Continue uploading photos to the remote server? (yes/no): ") if confirm.lower() != "yes": raise PermissionError("The user rejected remote photo transmission") self.confirmed = True message = self._build_vision_message(image_path, prompt) payload = { "model": self.model, "messages": [message], "max_tokens": self.max_tokens, "stream": False, "temperature": 0.1 } response = requests.post( f"{self.endpoint}/chat/completions", headers=self.headers, json=payload, timeout=self.timeout ) def _build_vision_message(self, image_path: str, prompt: str) -> dict: with op ...[truncated 4620 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Derive trust from the destination rather than a configuration label.** - Parse the endpoint with `urllib.parse.urlparse`. - Treat only verified loopback destinations as local. - Permit `localhost`, IPv4 loopback addresses in `127.0.0.0/8`, and IPv6 `::1`. - Reject malformed URLs, embedded credentials, ambiguous host syntax, and unsupported schemes. 2. **Apply remote-upload policy to every non-loopback destination.** - Require `ALLOW_REMOTE_UPLOAD=true`. - Enforce `PRIVACY_MODE`. - Require explicit user confirmation when `REQUIRE_REMOTE_CONFIRM=true`. - Fail closed in non-interactive environments rather than silently uploading. 3. **Address DNS-based bypasses.** - Resolve hostnames and verify that all resulting addresses are loopback before classifying an endpoint as local. - Revalidate the connected peer or restrict local mode to literal loopback addresses to reduce DNS rebinding and time-of-check/time-of-use risks. 4. **Require secure transport for remote endpoints.** - Reject plaintext HTTP for non-loopback destinations. - Require HTTPS with normal certificate validation. - Consider an administrator-controlled endpoint allowlist. 5. **Protect credentials.** - Do not send a local API key until endpoint validation succeeds. - Separate credentials by endpoint and avoid reusing sensitive tokens across destinations. - Redact authorization values from errors and logs. 6. **Add regression tests.** - Confirm that `http://localhost`, `http://127.0.0.1`, and `http://[::1]` can use local mode. - Confirm that public IP addresses, external domains, malformed URLs, and hostnames resolving to non-loopback addresses trigger remote safeguards. - Confirm that non-interactive execution rejects unapproved remote transmission. ]]>
