T01 · Skill Instruction Hijacking
Warning
- Location
- src/protocol.rs:81
- Finding
- Untrusted Web Content Is Presented as Ready-to-Use Agent Output## Vulnerability Details **File Location**: `src/protocol.rs:81-91`; related unsafe usage instructions at `SKILL.md:140` and `SKILL.md:178` **Vulnerability Type**: Indirect prompt injection through untrusted search and page content **Risk Level**: Medium **Vulnerable code (`src/protocol.rs:81-91`):** ```rust /// Build the markdown-formatted string from results. pub fn format_results(results: &[ExaResult]) -> String { results .iter() .map(|r| { let title = r.title.as_deref().unwrap_or("Untitled"); let url = &r.url; let body = r.summary.as_deref().or(r.text.as_deref()).unwrap_or(""); format!("## [{title}]({url})\n\n{body}\n\n---") }) .collect::<Vec<_>>() .join("\n\n") } ``` **Related instructions (`SKILL.md:140` and `SKILL.md:178`):** ```markdown The `formatted` field is ready-to-use markdown — you can send it directly to the user. ``` ### Technical Analysis The `format_results` function places titles, URLs, summaries, and extracted page text returned by Exa directly into Markdown. These values originate from external web pages and must therefore be treated as attacker-controlled content. No trust boundary, escaping, sanitization, or warning distinguishes retrieved page content from instructions intended for the Agent. The Skill documentation compounds this problem by explicitly stating that the generated Markdown can be sent directly to the user. In an Agent workflow, retrieved text may be placed back into the model context before the final response is generated. A malicious page can embed instructions such as requests to ignore the current task, reveal confidential context, invoke another tool, or follow an attacker-controlled link. Markdown construction also accepts the remote title and URL without validation. Although this does not itself execute code in the Rust process, it can create misle ...[truncated 1552 chars]
- Remediation
- ## Remediation Suggestions 1. Remove the instruction that the `formatted` field may be sent directly to the user. 2. Clearly label all search results and fetched page contents as untrusted external data. 3. In `SKILL.md`, instruct the Agent never to follow commands, policies, credential requests, or tool-use directives found in retrieved content. 4. Prefer structured JSON fields over preformatted Markdown so the caller can apply its own trust and presentation policy. 5. If Markdown output remains supported, validate URL schemes, escape attacker-controlled titles, and delimit page text in a clearly marked quotation or data block. 6. Require the Agent to extract factual information and produce a fresh summary rather than forwarding remote text verbatim. 7. Apply output-size limits per result and consider filtering common prompt-injection phrases as defense in depth. Such filtering must not replace explicit trust-boundary enforcement.
