T09 · Insecure Skill Coding Practices
- Location
cms_search.py:41- Finding
Untrusted Remote Search Content Is Emitted Without Validation or Isolation
- Content
View full analysis
str: result = (obj.get("result") or "").strip() source = (obj.get("source") or "").strip() lines = [] if result: lines.append(result) if source: lines.append(f"\n来源: {source}") return "\n".join(lines).strip() + "\n" ``` The related workflow directs the agent to use and synthesize these results: ```markdown 1. 根据问题、上下文、实体别名、时间范围和证据需求确定搜索词。 2. 简单事实搜索 1 次;需要总结、比较、验证或追踪最新信息时,拆成 2-7 个维度。 3. 每个搜索词分别调用一次 `cms_search.py`;完成后合并、去重并交叉验证结果。 ``` ### Technical Analysis The HTTP response is controlled by the remote search service and may incorporate attacker-controlled indexed web content. After JSON parsing, the script extracts the `result` and `source` fields and prints them directly as Markdown. It does not: - Validate that the response conforms to an expected schema. - Explicitly identify returned text as untrusted data. - Delimit remote content from agent instructions. - Prevent instruction-like text from being presented to the consuming agent. - Enforce a maximum response-body size before calling `resp.read()`. Consequently, a compromised search service or poisoned indexed page could supply instruction-like content that the agent might treat as authoritative directions rather than search evidence. This is an indirect prompt-injection risk. The Python script itself does not evaluate the response as code or directly invoke additional tools, so ...[truncated 2049 chars]- Remediation
View remediation
MAX_RESPONSE_BYTES: raise SystemExit("CMS response exceeds the permitted size.") body_bytes = resp.read(MAX_RESPONSE_BYTES + 1) if len(body_bytes) > MAX_RESPONSE_BYTES: raise SystemExit("CMS response exceeds the permitted size.") body = body_bytes.decode("utf-8", errors="replace") try: obj = json.loads(body) except json.JSONDecodeError: raise SystemExit("CMS returned invalid JSON.") if not isinstance(obj, dict): raise SystemExit("CMS returned an unexpected response structure.") result = obj.get("result", "") source = obj.get("source", "") if not isinstan ...[truncated 474 chars]
