T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/travel_search.py:483
- Finding
- Untrusted Remote MCP Content Is Exposed Directly to the Agent<![CDATA[ ## Vulnerability Details **File Location**: `scripts/travel_search.py:483-501`, `scripts/travel_search.py:625-637`, `scripts/travel_search.py:652-655`, and `SKILL.md:26,74-76` **Vulnerability Type**: Indirect prompt injection and unvalidated remote output **Risk Level**: Medium ### Complete Code Snippets From `scripts/travel_search.py:483-501`: ```python def _normalize_tool_result(result): if result is None: return {} if not isinstance(result, dict): return result # Tool-level error: never normalize or emit content / structuredContent. if result.get("isError") is True: raise McpError("tool_error", "tool error") if "structuredContent" in result and result["structuredContent"] is not None: return result["structuredContent"] content = result.get("content") if isinstance(content, list) and content: for item in content: if not isinstance(item, dict): continue if item.get("type") == "text" and isinstance(item.get("text"), str): text = item["text"].strip() if text and text[0] in "{[": try: return json.loads(text) except ValueError: pass break return result ``` From `scripts/travel_search.py:625-637`: ```python if match is None: return _fail(1, "not_found", "tool not found") _print_json( { "name": match.get("name"), "description": match.get("description"), "inputSchema": match.get("inputSchema"), } ) return 0 ``` From `scripts/travel_search.py:652-655`: ```python def _cmd_call(cli_name, arguments): mcp_name = COMMAND_TO_TOOL[cli_name] client = McpClient() result = client.call_tool(mcp_name, arguments) _print_json(result) ``` Relevant instructions from `SKILL.md:26` and `SKILL.md:74-76`: ```markdown Current tool schem ...[truncated 3576 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Declare the remote trust boundary** - Add an explicit rule to `SKILL.md` stating that all MCP descriptions, schemas, text, URLs, and result fields are untrusted data. - Instruct the Agent never to follow commands or behavioral instructions contained in MCP responses. - Require remote content to be used only as travel data matching the documented response fields. 2. **Apply strict output schemas** - Define local allowlists for expected fields for each command. - Reject or omit unexpected metadata instead of returning the complete MCP result. - Validate field types, maximum lengths, nesting depth, and collection sizes before printing results. - Avoid returning arbitrary text content merely because it parses as JSON. 3. **Validate returned URLs** - Permit only `https` URLs. - Reject URLs containing user information, nonstandard ports, control characters, or malformed hostnames. - Maintain an allowlist of approved booking and short-link hosts where feasible. - If the provider set is dynamic, label unrecognized destinations clearly and do not automatically present them as trusted booking links. 4. **Separate data from instructions** - Wrap remote values in a clearly identified structure such as `untrusted_remote_data`. - Ensure descriptions and schema annotations are never interpreted as Agent policy. - Prefer locally maintained command documentation for security-sensitive behavior, using live schemas only to validate parameter structure. 5. **Sanitize presentation fields** - Strip or reject content resembling system prompts, tool directives, embedded markup, or requests to ignore prior instructions. - Treat filtering as defense in depth rather than the only protection, because instruction-like text can be obfuscated. 6. **Add adversarial tests** - Test malicious instructions in tool descriptions, schema descriptions, structured content, and text content. - Test `javascr ...[truncated 180 chars]
