T09 · Insecure Skill Coding Practices
- Location
scripts/rag_synthesize.py:67- Finding
Unvalidated LLM Endpoint Can Receive API Credentials and Private RAG Content
- Content
View full analysis
Vulnerability Details
File Location:
scripts/rag_synthesize.py, lines 67–90
Vulnerability Type: Arbitrary outbound endpoint and sensitive-data disclosure
Risk Level: MediumVulnerable Code
python key = os.environ.get("OPENAI_API_KEY") base = os.environ.get("OPENAI_BASE_URL") model = os.environ.get("OPENAI_MODEL", "gpt-4o-mini") if not (key and base): return None evidence = "\n\n".join(f"[{i+1}] ({c['doc']})\n{t['text']}" for i, (s, c) in enumerate(hits)) prompt = ( "你是严谨的检索增强问答助手。只依据下面的【证据】回答," "并在句末用 [n] 标注引用编号。若证据不足,明确说不知道。\n\n" f"【证据】\n{evidence}\n\n【问题】\n{question}\n\n【回答】" ) payload = {"model": model, "messages": [{"role": "user", "content": prompt}], "temperature": 0.2} req = urllib.request.Request( base.rstrip("/") + "/chat/completions", data=json.dumps(payload).encode("utf-8"), headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, ) try: with urllib.request.urlopen(req, timeout=30) as resp: data = json.loads(resp.read().decode("utf-8")) return data["choices"][0]["message"]["content"].strip() except Exception as e: print(f"⚠️ LLM 调用失败,回退抽取式:{e}") return NoneTechnical Analysis
The value of
OPENAI_BASE_URLis used directly to construct the outbound API URL without validating its scheme, hostname, resolved address, or trust level. The request includes theOPENAI_API_KEYas a bearer token. Its body contains the user's question, retrieved document names, and retrieved document contents.An attacker who can influence this environment variable can redirect the request to an attacker-controlled server. The code also accepts plain HTTP URLs, allowing the authorization token and RAG data to be exposed through network interception. A URL targeting an internal service could additionally cause the application to issue an unintended server-side request, although the fixed
/chat/completionssuffix and JSON request format limit the reachable interfac ...[truncated 1468 chars]- Remediation
View remediation
Remediation Suggestions
- Parse the configured URL with
urllib.parse.urlsplitand permit onlyhttps. - Reject malformed URLs, embedded user information, fragments, unexpected ports, and unsupported schemes.
- Maintain an explicit allowlist of trusted LLM API hostnames rather than accepting arbitrary destinations.
- Resolve the hostname and reject loopback, link-local, multicast, unspecified, and private-network addresses unless an administrator has explicitly enabled a documented private endpoint.
- Revalidate redirects or disable them so a trusted URL cannot redirect requests to an untrusted host.
- Display the destination and explain that the question and retrieved document excerpts will leave the machine before the first external request; require explicit user consent.
- Apply data minimization by limiting excerpt size and allowing users to exclude sensitive documents from external generation.
- Avoid sending the API key over plain HTTP under all circumstances.
- Document precisely which fields are transmitted and provide a configuration option that forcibly disables network generation.
- Use provider credentials with minimal permissions, quotas, rotation procedures, and monitoring to constrain the impact of disclosure.
- Parse the configured URL with
