T09 · Insecure Skill Coding Practices
- Location
scripts/wechat_send.py:638- Finding
Private WeChat transcripts and API credentials can be transmitted to an unrestricted endpoint
- Content
View full analysis
Vulnerability Details
File Location:
scripts/wechat_send.py, lines 638–760
Vulnerability Type: Unrestricted transmission of sensitive information to a configurable network endpoint
Risk Level: HighComplete Code Snippet
python def normalize_endpoint(base_url: str) -> str: base = (base_url or "").strip() if not base: base = "https://api.openai.com/v1" base = base.rstrip("/") if base.endswith("/chat/completions"): return base if not base.endswith("/v1"): base = base + "/v1" return base + "/chat/completions" def request_llm_reply( transcript: str, contact: str, api_key: str, api_base: str, model: str, system_prompt: str, ) -> str: if not api_key: raise RuntimeError("Missing API key. Set OPENAI_API_KEY or pass --api-key.") if not model: raise RuntimeError("Missing model name. Set OPENAI_MODEL or pass --model.") prompt = ( f"Contact: {contact}\n" "Recent visible WeChat transcript:\n" f"{transcript}\n\n" "Write the next reply message only. " "Do not add quotes, prefixes, or explanations." ) body = { "model": model, "temperature": 0.7, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt}, ], } request = urllib.request.Request( normalize_endpoint(api_base), data=json.dumps(body).encode("utf-8"), headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", }, method="POST", ) try: with urllib.request.urlopen(request, timeout=60) as response: payload = json.loads(response.read().decode("utf-8")) except urllib.error.HTTPError as exc: detail = exc.read().deco ...[truncated 3602 chars]- Remediation
View remediation
Remediation Suggestions
- Require
httpsand reject HTTP, file, and other URL schemes. - Restrict destinations to an explicit allowlist of trusted LLM hosts, or require a deliberate security override for custom endpoints.
- Display the destination hostname and the categories of data being transmitted before smart-reply begins, and obtain explicit user consent.
- Do not inherit
OPENAI_BASE_URLsilently in sensitive workflows; require explicit endpoint configuration or clearly report environment-derived configuration. - Use a dedicated, least-privileged API key with provider-side usage and spending limits.
- Add transcript minimization and redaction controls for credentials, financial information, health information, and other sensitive data.
- Avoid including the contact identifier unless it is necessary for reply generation.
- Add tests confirming that plaintext and unapproved endpoints are rejected.
- Require
