Back to skill

Security audit

Paper Assistant

Security checks for vulnerabilities and agentic risk

Overview

This skill fetches public paper metadata, asks the agent to recommend a paper, and keeps a small local record of pushed paper IDs; the behavior is disclosed and proportionate, with a prompt-injection caution for untrusted paper text.

Before installing, be aware that the skill contacts OpenReview and arXiv, reads public paper metadata into the agent context, and updates data/pushed.json to avoid repeats. It is reasonable to install for this workflow, but users should add or follow a rule that paper titles, abstracts, authors, and URLs are untrusted content and should not be treated as instructions.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

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. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
声明描述的是一个面向论文检索、筛选与推荐的技能,重点在于发现和挑选最新论文;而实际代码只是一个本地维护脚本,把给定的 paper_id 追加到 pushed.json 里,避免重复推送。它既不访问论文数据源,也不进行任何检索、排序、推荐或强化学习/Agent 方向分析。虽然“用于后续推送”与“标记已推送”在工作流上有关联,但该代码块本身的主要目的与声明的核心能力明显不一致,因此应判定为描述与行为不匹配。

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill invokes network access to fetch papers and writes local state to data/pushed.json, but it declares no permissions or allowed-tools scope. This creates an under-specified trust boundary: an agent may be granted broader file or network capabilities than users expect, increasing the risk of unintended external requests or local file modification.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The manifest description is written as a directive in Chinese and the rest of the skill content consistently specifies behavior and outputs in Chinese, with no indication that users may choose another language. This creates a locale/language policy concern because the skill appears to assume a fixed language without user opt-in or documented regional justification.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill instructs the agent to append IDs to data/pushed.json and even create the file if missing, without clearly warning the user that local files will be modified. Hidden state changes can affect reproducibility, surprise users, and become dangerous when chained in automated pipelines because the agent silently persists data across runs.

Description-Behavior Mismatch

Medium
Confidence
85% confidence
Finding
The manifest describes a skill for finding, filtering, or recommending recent papers for later reading or pushing, but this script mutates local state by creating and updating data/pushed.json. Persistently marking items as already pushed is a state-management behavior not reflected in the manifest’s stated functionality.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The module docstring describes the skill entirely in Chinese, indicating a fixed language presentation for the skill's user-facing description. There is no indication of user opt-in, language selection, or a documented region-specific reason for restricting the skill to Chinese.

Static analysis

No suspicious patterns detected.