Back to skill

Security audit

文档问答助手

Security checks for vulnerabilities and agentic risk

Overview

This document QA skill is related to its stated purpose, but it should be reviewed because crafted PDF filenames can trigger arbitrary Python execution and the documentation overstates its capabilities.

Only use this skill on documents and directories you fully trust, especially PDFs. Treat its claims about Word support, semantic retrieval, indexing, summaries, and cross-document validation as inaccurate until fixed. The PDF handling should be corrected before normal installation or use.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/doc_qa.py:12
Finding

Arbitrary Python Code Execution Through an Unsafely Interpolated PDF Path

Content
View full analysis

Vulnerability Details

File Location: scripts/doc_qa.py, lines 12-14
Vulnerability Type: Python interpreter argument injection
Risk Level: High

Vulnerable Code:

python
result = subprocess.run(["python3", "-c",
    f"import pdfplumber; print(pdfplumber.open('{path}').pages[0].extract_text())"],
    capture_output=True, text=True)

Technical Analysis

The PDF path is inserted directly into Python source code passed to a child interpreter through the python3 -c option. Although subprocess.run() does not invoke a command shell here, the value is still interpreted as executable Python code.

The path value can originate from the user-supplied --docs argument or from filenames returned by os.listdir() when a document directory is processed. A malicious filename containing a single quote, closing syntax, and additional Python statements can escape the pdfplumber.open() string literal.

For example, a filename shaped like the following can alter the generated Python program:

text
x'); __import__('os').system('id'); #.pdf

When joined to the document directory and interpolated into the command, the resulting child-process source can execute the injected statement. The broad exception handler and captured output do not prevent execution; they may only conceal errors or command output after the payload runs.

Attack Path

  1. An attacker creates or supplies a file with a .pdf extension and a filename containing valid Python injection syntax.
  2. The attacker places that file in a directory that the victim will process, or convinces the victim to pass its path through --docs.
  3. qa() enumerates the file and passes its path to read_file().
  4. read_file() interpolates the untrusted path into source code supplied to python3 -c.
  5. The child Python interpreter parses and executes the attacker-controlled statements.
  6. The payload runs with the same operating-system ...[truncated 780 chars]
Remediation
View remediation

Remediation Suggestions

Import and use pdfplumber directly rather than constructing a second Python program:

python
elif ext == ".pdf":
    try:
        import pdfplumber
        with pdfplumber.open(path) as pdf:
            if not pdf.pages:
                return ""
            return pdf.pages[0].extract_text() or ""
    except Exception:
        return "[PDF parsing unavailable]"

If a separate process is required for isolation, pass the document path as a distinct argument and retrieve it through sys.argv; never interpolate it into executable source:

python
result = subprocess.run(
    [
        "python3",
        "-c",
        (
            "import sys, pdfplumber; "
            "p = pdfplumber.open(sys.argv[1]); "
            "print(p.pages[0].extract_text() or '')"
        ),
        path,
    ],
    capture_output=True,
    text=True,
    check=False,
    timeout=30,
)

Additional hardening should include:

  • Resolve and validate document paths against an explicitly permitted root directory.
  • Reject unsupported file types rather than attempting to read every unknown format as UTF-8 text.
  • Apply subprocess timeouts and resource limits to untrusted document parsing.
  • Catch specific parsing and I/O exceptions instead of using a bare except.
  • Run document parsers in a sandbox or low-privilege worker when processing attacker-controlled files.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

该技能的总体方向确实与“文档问答”相关,但描述显著高于实际实现。代码的核心行为是:读取本地文件内容,按字符/关键词在行中检索,返回相关片段和来源。这可以部分支撑“从文档中查找答案、基于文档回答问题、跨多个文档综合查询”的最基础版本,但并不构成所宣称的知识库检索、交叉验证、一致性验证和摘要生成。另外,文件格式支持也与描述不符:Markdown/TXT可读,PDF支持非常有限,Word实际上未实现。因此应判定为描述与实际行为存在实质性不匹配。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding

The skill advertises shell and file-reading style usage through example commands but does not declare any explicit tool scope or permission boundaries. In an agent ecosystem, this can lead to overbroad runtime access, making accidental local file exposure or unintended command execution more likely if the host grants default capabilities.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest description and main skill description are entirely in Chinese, and all example prompts are written in Chinese, which indicates the skill is presented as Chinese-only. The file does not state that this is a region-specific skill or offer any language/locale opt-in, so it appears to impose a locale preference without user choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file description and user-facing strings are written in Chinese, and the program always returns answers in Chinese regardless of user preference. This is a natural-language policy issue because it imposes a specific language without offering a choice or documenting a justified locale restriction.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest advertises support for PDF/Word/Markdown/TXT, knowledge-base retrieval, multi-document cross-validation, consistency verification, and summary generation. In practice, the code reads plain text files, attempts first-page PDF extraction only, has no Word-specific parsing, no knowledge-base integration, no consistency checking logic, and no summarization beyond returning top matching excerpts.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Spawning a subprocess for PDF parsing is unnecessary for the stated local QA purpose and expands the attack surface, especially because the subprocess is driven by untrusted file paths. While subprocess use alone is not always a flaw, here it is directly tied to the unsafe python3 -c pattern and increases the chance of command/code-execution abuse or unexpected runtime behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code launches a subprocess to parse PDF content, which is a safety-relevant operation for code files under the rule because it executes an external command. Although the skill prints final results, there is no confirmation prompt, warning, or inline documentation disclosing that PDF input triggers subprocess execution.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The PDF path is interpolated directly into Python code passed to python3 -c, so a crafted filename containing quotes or Python syntax can break out of the string and execute arbitrary code. In a document-QA skill that processes local user-supplied files, this creates a realistic code-execution path from an untrusted document path.

Content

Scanner excerpt · scripts/doc_qa.py (reported line 13)May include surrounding context.

python
elif ext == ".pdf":
        try:
            import subprocess
            result = subprocess.run(["python3", "-c",
                f"import pdfplumber; print(pdfplumber.open('{path}').pages[0].extract_text())"],
                capture_output=True, text=True)
            return result.stdout or "[PDF读取失败]"

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The generated answer format is always presented in Chinese, with no mechanism for locale selection or opt-in. Under the policy rule, hard-coding a single language for user-facing output is a violation unless the skill offers a choice or clearly documents a justified regional constraint.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

清单描述在 L03 将技能范围限定为本地 PDF/Word/Markdown/TXT 文档问答,而核心能力列表在 L12 又写明支持 CHM。即使这是文档层面的扩展而非代码实现,它仍然改变了技能对外宣称的处理范围,和 manifest 的描述不一致。

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.