T09 · Insecure Skill Coding Practices
- Location
scripts/embed.py:67- Finding
Remote embedding endpoints do not enforce HTTPS
- Content
View full analysis
None: """Ensure the URL matches the expected official endpoint for the provider.""" parsed = urlparse(url) domain = parsed.netloc.split(':')[0] allowed = ALLOWED_DOMAINS.get(provider_name, []) if allowed and domain not in allowed: # If it's a known provider but unknown domain, check if it's explicitly allowed in config # For now, we raise a security warning and exit unless it's a local/custom case. print(f"⚠️ Security Warning: Provider '{provider_name}' is using an unofficial endpoint: {domain}") print(f" Official domains: {', '.join(allowed)}") print(" To bypass this, use a custom provider name in config or verify the URL.") sys.exit(1) ``` OpenAI subsequently sends the note text and API key to the validated URL: ```python url = provider["url"].rstrip("/") + "/embeddings" validate_url(url, "openai") payload = json.dumps({"model": model, "input": text}).encode() req = urllib.request.Request( url, data=payload, headers={ "Content-Type": "application/json", "Authorization": f"Bearer {api_key}", }, method="POST", ) with urllib.request.urlopen(req, timeout=60) as resp: data = json.loads(resp.read()) return data["data"][0]["embedding"] ``` Gemini uses the same validation mechanism before transmitting note text and its API key: ```python base_url = provider["url"].rstrip("/") url = f"{base_url}/v1beta/models/{model}:embedContent" validate_url(url, "gemini") payload = json.dumps({ "content": {"parts": [{"text": text}]}, }).encode() req = urllib.request.Request( url, data=payload, headers={ "Content-Type": "application/json", "x-goog-api-key": api_key, } ...[truncated 2512 chars]- Remediation
View remediation
None: parsed = urlparse(url) hostname = parsed.hostname if not hostname: raise ValueError("Provider URL must contain a valid hostname") if provider_name in {"openai", "gemini"} and parsed.scheme != "https": raise ValueError(f"{provider_name} endpoints must use HTTPS") if provider_name == "ollama": if parsed.scheme not in {"http", "https"}: raise ValueError("Ollama endpoint must use HTTP or HTTPS") if hostname not in {"localhost", "127.0.0.1", "::1"}: raise ValueError("Ollama endpoint must resolve to loopback") allowed = ALLOWED_DOMAINS.get(provider_name, []) if allowed and hostname not in allowed: raise ValueError("Provider hostname is not allowlisted") ``` 2. Reject URLs containing embedded credentials, unexpected fragments, or unsupported schemes. 3. Consider disabling automatic cross-origin redirects or revalidating every redirect target before sending sensitive headers and request bodies. 4. Keep plaintext HTTP limited to verified loopback Ollama endpoints. 5. Explicitly warn users before enabling a remote provider that note content and search queries will be disclosed to that provider. 6. Add automated tests covering HTTP rejection, malformed URLs, user-information syntax, IPv6 loopback, ports, and redirect behavior. ]]>
