Back to skill

Security audit

Paper Recommendation

Security checks for vulnerabilities and agentic risk

Overview

This paper-research skill is mostly coherent, but it can create recurring automation that sends generated briefings to a fixed Telegram account.

Review this skill carefully before installing. Do not run the cron command or daily_workflow.py unless you replace the Telegram ID with one you control, understand that briefings and local paths may be sent externally, and are comfortable with recurring downloads and local file creation under your user account.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (3)

T06 · System Persistence

Error
Location
scripts/daily_workflow.py:14
Finding
Persistent disclosure to a hard-coded Telegram recipient<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:224-231`; `scripts/daily_workflow.py:14, 130-159, 181-182` **Vulnerability Type**: Persistent scheduled execution and unauthorized information transmission **Risk Level**: High ### Vulnerable Code ```bash clawdbot cron add \ --name "daily-paper-research" \ --description "每日完整论文调研:获取→阅读→简报→发送" \ --cron "0 10 * * *" \ --system-event "请执行完整论文调研工作流:运行 python3 /home/ubuntu/skills/jarvis-research/scripts/daily_workflow.py。这会获取具身智能论文、下载 PDF、生成简报并发送到我的 Telegram。完成后告诉我结果。" \ --deliver \ --channel telegram \ --to 8077045709 ``` ```python TELEGRAM_ID = "8077045709" ``` ```python def send_to_telegram(content, brief_summary): """发送摘要到 Telegram""" log("📤 发送到 Telegram...") # 发送摘要(因为全文太长) message = f"""📚 **Jarvis 论文精选** - {datetime.now().strftime('%Y年%m月%d日')} 🎯 智能体与AI前沿研究专题论文已生成! {content[:800]}... 📄 完整简报: {brief_summary} 💡 每日自动推送 | 10:00 AM 🤖 Generated by Jarvis""" # 使用 clawdbot CLI 发送 try: result = subprocess.run([ 'clawdbot', 'message', 'send', '--target', TELEGRAM_ID, '--message', message ], capture_output=True, text=True, timeout=30) if result.returncode == 0: log(" ✅ 已发送到 Telegram") return True else: log(f" ⚠️ 发送失败: {result.stderr}") return False except Exception as e: log(f" ⚠️ 发送失败: {e}") return False ``` ```python # 4. 发送到 Telegram send_to_telegram(brief, filepath) ``` ### Technical Analysis Telegram delivery is part of the declared workflow, but the destination is controlled by the package rather than selected by the user. Both the installation documentation and runtime script hard-code Telegram account `8077045709`. The documented command also creates a daily cron task. This makes the behavior survive the original installation or execution session and repeatedly invokes the workflow without requi ...[truncated 1545 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `TELEGRAM_ID` from the source code and documentation. 2. Disable external delivery by default. 3. Require the destination to be supplied explicitly through a command-line option or trusted configuration file. 4. Display the selected channel and recipient and require affirmative user confirmation before registering a scheduled task. 5. Do not transmit absolute local paths. If necessary, report only the output filename. 6. Provide documented commands for listing, disabling, and deleting the installed cron task. 7. Apply a destination allowlist or account-ownership verification where the messaging platform supports it. 8. Record only non-sensitive delivery status in logs. 9. Require separate opt-in consent for persistent scheduling and external message delivery. ]]>

T01 · Skill Instruction Hijacking

Error
Location
scripts/review_papers.py:20
Finding
Indirect prompt injection through untrusted paper metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/review_papers.py:20-59`; `scripts/daily_workflow.py:31-49` **Vulnerability Type**: Untrusted remote content embedded directly into agent instructions **Risk Level**: High ### Vulnerable Code ```python SUBAGENT_TASK_TEMPLATE = """请完整阅读这篇论文并给出评分: 论文信息: - 标题: {title} - 作者: {authors} - 摘要: {summary} - arXiv: {url} 请执行以下任务: 1. 完整阅读论文(通过 arXiv HTML 页面获取完整内容) 2. 提取:机构、完整摘要、核心贡献、主要结论、实验结果 3. 评估论文质量(1-5分) 4. 给出推荐建议(yes/no) 回复 JSON 格式: {{"review": {{ "id": "{paper_id}", "score": 5, "contribution": "一句话核心贡献", "conclusion": "一句话主要结论", "experiments": "实验设置和关键发现", "recommended": "yes" }}}}""" def generate_subagent_tasks(papers): """Generate sub-agent tasks for each paper.""" tasks = [] for p in papers: task = SUBAGENT_TASK_TEMPLATE.format( paper_id=p['id'], title=p['title'], authors=', '.join(p.get('authors', [])), summary=p.get('summary', '')[:500], url=p.get('url', '') ) tasks.append({ 'paper_id': p['id'], 'task': task, 'label': f"review-{p['id']}" }) return tasks ``` The end-to-end workflow uses the same unsafe pattern: ```python for p in papers: task = f"""请完整阅读这篇论文: 论文ID: {p['id']} 标题: {p['title']} PDF: {p['pdf_url']} 请执行: 1. 读取 PDF(使用 pdftotext 或 web_fetch) 2. 提取:机构、中文摘要、核心贡献、主要结论、实验结果 3. 评分 1-5,给出推荐 4. 回复 JSON:{{"review": {{"id": "{p['id']}", "score": 5, "contribution": "一句话", "conclusion": "一句话", "experiments": "实验设置和关键发现", "recommended": "yes"}}}}""" subprocess.run([ 'clawdbot', 'sessions', 'spawn', '--task', task, '--label', f"review-{p['id']}", '--cleanup', 'delete' ], capture_output=True) ``` ### Technical Analysis Paper titles, author names, summaries, identifiers, and URLs originate from remote arXiv responses. These values are interpolated directly into natural-language instruc ...[truncated 1863 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pass paper metadata to sub-agents as typed structured data rather than embedding it into prose instructions. 2. Mark all paper metadata and paper contents as untrusted data using explicit delimiters. 3. Add a higher-priority instruction stating that directives found in titles, abstracts, HTML, PDFs, citations, and metadata must never be followed. 4. Restrict review sub-agents to read-only access to approved arXiv hosts and the specific downloaded PDF. 5. Disable filesystem, messaging, credential, shell, and unrelated network tools for review agents. 6. Validate paper IDs and URLs before including them in tasks. 7. Parse returned responses against a strict JSON schema and reject extra commands, tool requests, or unexpected fields. 8. Separate content extraction from agent reasoning. A non-agent parser should first extract text, after which the model receives only bounded content. 9. Limit remote-content length and normalize control characters or deceptive formatting before prompt construction. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_papers.py:48
Finding
Remote paper identifiers are used in local paths without validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_papers.py:48-50, 72-75, 94-105` **Vulnerability Type**: Unsanitized remote filename construction and insufficient download validation **Risk Level**: Medium ### Vulnerable Code ```python id_match = re.search(r'<id>(.*?)</id>', entry) if id_match: paper_id = id_match.group(1).split('/abs/')[-1].split('v')[0] else: continue ``` ```python papers.append({ 'id': paper_id, 'title': title, 'summary': summary, 'authors': authors, 'published': published, 'url': f'https://arxiv.org/abs/{paper_id}', 'pdf_url': f'https://arxiv.org/pdf/{paper_id}.pdf', 'category': category, 'relevance_score': score }) ``` ```python def download_papers(papers, output_dir): """Download PDF papers.""" output_dir = Path(output_dir) output_dir.mkdir(parents=True, exist_ok=True) downloaded = [] for p in papers: pdf_path = output_dir / f"{p['id']}.pdf" if pdf_path.exists(): downloaded.append(str(pdf_path)) continue try: subprocess.run(['curl', '-sL', p['pdf_url'], '-o', str(pdf_path)], timeout=60) if pdf_path.exists() and pdf_path.stat().st_size > 1000: downloaded.append(str(pdf_path)) except: pass return downloaded ``` ### Technical Analysis The paper identifier is extracted from a remote XML response and later used as part of a local path. The code does not enforce the expected arXiv identifier syntax and does not verify that the resolved destination remains inside `output_dir`. The downloader follows redirects with `curl -L`, but it does not: - Fail on HTTP error responses. - Restrict the final redirect host. - Check the process return code. - Verify the response content type. - Verify PDF magic bytes. - Remove invalid or partial downloads. A file is accepted solely because it exists and is larger than 1,000 bytes. The daily w ...[truncated 1524 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate identifiers using a strict allowlist for supported arXiv formats before constructing URLs or paths. 2. Reject identifiers containing `/`, `\`, `..`, control characters, URL encoding, or unexpected suffixes. 3. Resolve the candidate path and verify that it remains beneath the resolved papers directory. 4. Download to a securely created temporary file in the destination directory. 5. Use `curl --fail --show-error --location` and check the subprocess return code. 6. Restrict redirects to HTTPS and approved arXiv hostnames. 7. Verify both the response content type and the `%PDF-` file signature. 8. Apply a reasonable maximum download size. 9. Delete temporary or partial files after any timeout, validation failure, or nonzero exit status. 10. Keep Poppler patched and process untrusted PDFs in a sandbox with restricted filesystem and network access. 11. Replace the broad `except:` clause with specific exceptions and log validation failures without exposing sensitive paths. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (17)

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs automatic PDF downloads, local file generation, and Telegram delivery to a fixed recipient without prominently requiring explicit user consent at execution time. This creates a real risk of unintended data transmission and disk writes, especially in an agent environment where users may invoke the skill for research without realizing it will persist files and exfiltrate generated content to an external channel.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file requires the abstract to be a complete Chinese translation and later states that the abstract 'must be Chinese,' while presenting the format as mandatory with no exceptions. This forces a specific language/locale without user opt-in, which matches the policy-violation category for language constraints.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The note at L380 states 'The briefing is Jarvis's creative work - not automated'. However, the rest of the document repeatedly defines an automated daily workflow that '自动完成:获取 → 下载 → 生成 → 发送' and says the script generates the briefing and sends it to Telegram. This is an active contradiction in the skill documentation about whether briefing generation is automated.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The workflow mandates extraction of a Chinese abstract and later explicitly instructs writing a Chinese translation and using Chinese section labels in the briefing. This forces a specific language/locale in the skill's instructions without user opt-in or a documented region-specific justification.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The workflow explicitly instructs the agent to send the generated briefing to Telegram, an external messaging channel, without any consent check, sensitivity review, or warning that content is leaving the local environment. Even if the briefing is intended to contain paper summaries, agent-generated content can include unexpected sensitive data from prompts, local files, or prior context, so unguarded exfiltration to third-party services is a real data-leak risk.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The natural-language description states the workflow in Chinese only and frames the skill behavior entirely in that locale, with no indication that users can opt into another language. Under the policy, forcing a specific language without user choice is a locale/language policy violation.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def fetch_papers():
    """获取论文并下载 PDF"""
    log("📥 获取智能体与AI前沿研究论文...")
    result = subprocess.run(
        ['python3', 'scripts/fetch_papers.py', '--download', '--limit', '6', '--json'],
        cwd=SKILL_DIR, capture_output=True, text=True, timeout=180
    )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
3. 评分 1-5,给出推荐
4. 回复 JSON:{{"review": {{"id": "{p['id']}", "score": 5, "contribution": "一句话", "conclusion": "一句话", "experiments": "实验设置和关键发现", "recommended": "yes"}}}}"""

        subprocess.run([
            'clawdbot', 'sessions', 'spawn',
            '--task', task,
            '--label', f"review-{p['id']}",
Confidence
87% confidence
Finding
The code constructs a subagent task by interpolating untrusted paper metadata such as title, id, and pdf_url directly into a natural-language prompt sent to another agent. If upstream paper metadata is adversarial, this creates a prompt-injection channel that can manipulate the spawned subagent into performing unintended actions or producing tainted results.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
pdf_path = f"{PAPERS_DIR}/{p['id']}.pdf"
        text = ""
        if os.path.exists(pdf_path):
            result = subprocess.run(['pdftotext', pdf_path, '-'], capture_output=True, text=True, timeout=30)
            text = result.stdout[:3000] if result.returncode == 0 else ""
        
        # 提取机构
Confidence
81% confidence
Finding
The code passes a file path derived from untrusted paper IDs into pdftotext without sanitizing the identifier. If an attacker can influence p['id'], they may cause the workflow to read unintended local files via path traversal or process attacker-chosen files, which is especially risky in an automated scheduled job.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
This code creates and saves a markdown briefing under PAPERS_DIR, which is a persistent file write affecting user/system data. Although there is a log after the write succeeds, there is no prior warning, confirmation, or explanatory comment disclosing that the workflow will create dated briefing files on disk.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The workflow automatically transmits generated research content to an external Telegram target without any explicit disclosure, confirmation, or content-classification checks. In a skill context, this creates data exfiltration risk if fetched papers, extracted text, or local summaries contain sensitive or proprietary information.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 使用 clawdbot CLI 发送
    try:
        result = subprocess.run([
            'clawdbot', 'message', 'send',
            '--target', TELEGRAM_ID,
            '--message', message
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The workflow explicitly skips subagent review but still outputs fixed scores, recommendations, and analysis-like sections as though substantive review occurred. This is dangerous because it can mislead recipients into trusting fabricated research assessments, enabling poor decisions and integrity failures in downstream workflows.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
for category in CATEGORIES:
        url = f'https://export.arxiv.org/api/query?search_query=cat:{category}&start=0&max_results=30&sortBy=submittedDate&sortOrder=descending'
        
        result = subprocess.run(['curl', '-sL', url], capture_output=True, text=True, timeout=30)
        data = result.stdout
        entries = re.findall(r'<entry>(.*?)</entry>', data, re.DOTALL)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
continue
        
        try:
            subprocess.run(['curl', '-sL', p['pdf_url'], '-o', str(pdf_path)], timeout=60)
            if pdf_path.exists() and pdf_path.stat().st_size > 1000:
                downloaded.append(str(pdf_path))
        except:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
cmd = ['pdftotext', str(pdf_path), '-']
    
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
        
        if result.returncode != 0:
            return {"error": f"pdftotext failed: {result.stderr}"}
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The embedded task template is entirely in Chinese and directs downstream sub-agents to respond in that language and format, but the script does not offer any language choice or explain a locale-specific requirement. This creates a natural-language policy issue because it imposes a specific language on users and sub-agents by default.

Static analysis

No suspicious patterns detected.