T01 · Skill Instruction Hijacking
Warning
- Location
- scripts/fetch_papers.py:83
- Finding
- Untrusted Paper Metadata Can Inject Instructions into the Agent Workflow<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:29-50`, `scripts/fetch_papers.py:83-105`, `scripts/fetch_papers.py:137-154`, and `scripts/fetch_papers.py:185-192` **Vulnerability Type**: Indirect prompt injection through attacker-controlled remote content **Risk Level**: Medium ### Vulnerable Code The OpenReview integration copies remotely supplied titles and abstracts directly into candidate records without marking, sanitizing, or isolating them as untrusted content: ```python # Extract fields title = fc.get("title", {}) title_val = title.get("value", "") if isinstance(title, dict) else str(title) abstract = fc.get("abstract", {}) abstract_val = abstract.get("value", "") if isinstance(abstract, dict) else str(abstract) authors = fc.get("authors", {}) authors_val = authors.get("value", []) if isinstance(authors, dict) else [] pdf = fc.get("pdf", {}) pdf_val = pdf.get("value", "") if isinstance(pdf, dict) else str(pdf) pdf_url = f"https://openreview.net{pdf_val}" if pdf_val else "" keywords = fc.get("keywords", {}) keywords_val = keywords.get("value", []) if isinstance(keywords, dict) else [] forum_id = note.get("forum", note.get("id", "")) papers.append({ "id": f"openreview:{forum_id}", "title": title_val, "authors": authors_val if isinstance(authors_val, list) else [authors_val], "abstract": abstract_val, "pdf": pdf_url, "venue": venue_val, "source": label, "keywords": keywords_val if isinstance(keywords_val, list) else [], }) ``` The same issue exists for arXiv metadata: ```python title = entry.find("a:title", ns).text.strip().replace("\n", " ") summary = entry.find("a:summary", ns).text.strip().replace("\n", " ") arxiv_id = entry.find("a:id", ns).text # e.g. http://arxiv.org/abs/2603.xxxxx ...[truncated 4520 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Add an explicit instruction boundary to `SKILL.md` stating that every field returned by OpenReview or arXiv is untrusted data and that commands found inside titles, abstracts, author names, keywords, URLs, or venue fields must never be followed. 2. Place candidate data in a rigidly delimited structure and instruct the model to analyze only the semantic research content. Delimiters alone are not a complete defense, but they reduce ambiguity when combined with explicit trust rules. 3. Require structured model output containing only a candidate ID and a short rationale. Reject free-form tool instructions or URLs returned by the model. 4. Validate the selected ID against the exact candidate set generated by `fetch_papers.py`. Resolve the title, PDF URL, source, and venue from the trusted candidate record rather than accepting model-generated replacements. 5. Allowlist downstream URL origins and schemes. For this workflow, accept only expected HTTPS hosts such as `openreview.net` and `arxiv.org`, and reject redirects to unexpected domains before passing a PDF to later stages. 6. Separate content evaluation from tool execution. A model that reads untrusted abstracts should not directly invoke messaging, filesystem, network, or execution tools. A deterministic controller should validate its structured decision before taking any action. 7. Apply field length limits and normalize control characters before sending metadata to the model. This does not prevent semantic injection by itself, but it reduces payload capacity and malformed-context attacks. 8. Add adversarial tests containing titles and abstracts with instructions such as “ignore previous instructions” and verify that the selected ID remains constrained to legitimate candidates and that no unauthorized tool action occurs. ]]>
