Back to skill

Security audit

Product Doc Reader

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real product-drawing extractor, but it can upload full engineering drawing images to third-party AI APIs by default and includes a hard-coded API credential.

Install only if you are comfortable with product drawings being sent to OpenRouter or Dashscope for Vision analysis. Prefer running with --text-only for confidential drawings, provide your own API credentials if Vision is needed, review the hard-coded credential issue, and avoid batch cleanup paths unless WORKSPACE and --temp-dir point to a safe disposable directory.

Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (35)

subprocess module call

Medium
Category
Dangerous Code Execution
Content
f.write(summary)
    
    # 清理
    subprocess.run(["rm", "-rf", str(TEMP_DIR)], check=True)
    
    print(f"\n✅ 完成!")
    print(f"   成功:{len(results)}/{len(PDF_FILES)}")
Confidence
95% confidence
Finding
The script recursively deletes TEMP_DIR using rm -rf, and TEMP_DIR is derived from WORKSPACE, which comes from an environment variable. If WORKSPACE is misconfigured or maliciously set, cleanup could remove unintended directories, causing destructive data loss beyond the intended temp folder.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
for line in result.stdout.split('\n'):
        if line.startswith('path'):
            downloaded_path = line.split('\t')[1].strip()
            subprocess.run(["mv", downloaded_path, str(output_path)], check=True)
            return True
    return False
Confidence
88% confidence
Finding
The script trusts a path string parsed from external tool output and feeds it directly into mv. Although shell injection is avoided, this still allows unsafe file operations if the downloader emits an unexpected or attacker-influenced path, potentially moving arbitrary local files into the knowledge-base workflow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
with open(summary_path, 'w', encoding='utf-8') as f:
        f.write(summary)
    
    subprocess.run(["rm", "-rf", str(TEMP_DIR)], check=True)
    
    print(f"\n✅ 完成!")
    print(f"   成功:{len(results)}/58")
Confidence
96% confidence
Finding
The script performs a recursive delete via `rm -rf` on a path derived from `WORKSPACE`, which comes from an environment variable. If `WORKSPACE` is manipulated or resolves unexpectedly, the deletion target can escape the intended temp area and remove arbitrary files or directories.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
for line in result.stdout.split('\n'):
        if line.startswith('path'):
            downloaded_path = line.split('\t')[1].strip()
            subprocess.run(["mv", downloaded_path, str(output_path)], check=True)
            return True
    return False
Confidence
94% confidence
Finding
The destination move uses `downloaded_path` parsed directly from external command output. A malicious or compromised `gog` binary, or unexpected output format, could cause the script to move an unintended local file into the knowledge-base workflow, resulting in file tampering or data exfiltration from local paths.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 5. 清理临时文件
    print(f"\n[4/4] 清理临时文件...")
    subprocess.run(["rm", "-rf", str(temp_dir)], check=True)
    print(f"  ✅ 已清理:{temp_dir}")
    
    # 完成
Confidence
96% confidence
Finding
The script performs `rm -rf` on a path ultimately influenced by environment/configuration (`WORKSPACE` and `--temp-dir`) without validating that the target is within a safe directory boundary. If an attacker or misconfiguration points `temp_dir` to an unexpected location, the cleanup step can recursively delete arbitrary files or directories.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
for line in result.stdout.split('\n'):
        if line.startswith('path'):
            downloaded_path = line.split('\t')[1].strip()
            subprocess.run(["mv", downloaded_path, str(output_path)], check=True)
            return True
    return False
Confidence
97% confidence
Finding
The script trusts `gog drive download` stdout to supply a filesystem path, then feeds that unvalidated path into `mv`. Because command output is untrusted input, a malicious or compromised `gog` binary, manipulated environment, or unexpected output format could cause arbitrary local files to be moved into the output location.

Tainted flow: 'cmd' from os.getenv (line 55, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
script_path = Path(WORKSPACE + "/skills/product-doc-reader/scripts/extract_hybrid.py")
    
    cmd = ["python3", str(script_path), str(pdf_path), "--stdout", "-f", "json"]
    result = subprocess.run(cmd, capture_output=True, text=True)
    
    try:
        json_str = result.stdout.strip()
Confidence
91% confidence
Finding
script_path is built from WORKSPACE, which is environment-controlled, and then executed with python3. An attacker who can influence WORKSPACE could redirect execution to an unintended script path and achieve arbitrary code execution in the context running this batch job.

Tainted flow: 'TEMP_DIR' from os.getenv (line 14, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
f.write(summary)
    
    # 清理
    subprocess.run(["rm", "-rf", str(TEMP_DIR)], check=True)
    
    print(f"\n✅ 完成!")
    print(f"   成功:{len(results)}/{len(PDF_FILES)}")
Confidence
98% confidence
Finding
TEMP_DIR depends on WORKSPACE from the environment, and the script passes it to recursive deletion. This creates a path-taint-to-destructive-action issue where a manipulated environment can cause deletion of arbitrary directories accessible to the process.

Tainted flow: 'md_path' from os.getenv (line 172, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
output_dir.mkdir(parents=True, exist_ok=True)
    md_path = output_dir / f"{drawing_no}.md"
    with open(md_path, 'w', encoding='utf-8') as f:
        f.write(md)
    
    return md_path
Confidence
80% confidence
Finding
The markdown output path is derived from KB_DIR, which in turn depends on WORKSPACE from the environment. If WORKSPACE is attacker-controlled, the script can be tricked into writing files outside the intended knowledge-base location, enabling unauthorized file creation or overwrite within accessible paths.

Tainted flow: 'summary_path' from os.getenv (line 193, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
summary += f"| {r['drawing_no']} | {r['model_no']} | {r['product']} |\n"
    
    summary_path = KB_DIR / "00-599 汇总.md"
    with open(summary_path, 'w', encoding='utf-8') as f:
        f.write(summary)
    
    # 清理
Confidence
80% confidence
Finding
summary_path is written under KB_DIR, which inherits from environment-controlled WORKSPACE. That means an attacker controlling runtime environment variables could redirect summary generation to unintended filesystem targets and overwrite files the process can access.

Tainted flow: 'cmd' from os.getenv (line 95, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
script_path = Path(WORKSPACE + "/skills/product-doc-reader/scripts/extract_hybrid.py")
    
    cmd = ["python3", str(script_path), str(pdf_path), "--stdout", "-f", "json"]
    result = subprocess.run(cmd, capture_output=True, text=True)
    
    try:
        json_str = result.stdout.strip()
Confidence
93% confidence
Finding
`script_path` is constructed from `WORKSPACE`, which is environment-controlled, and then executed with `python3`. An attacker who can influence `WORKSPACE` can redirect execution to an arbitrary Python script, leading to code execution under the script's privileges.

Tainted flow: 'TEMP_DIR' from os.getenv (line 14, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
with open(summary_path, 'w', encoding='utf-8') as f:
        f.write(summary)
    
    subprocess.run(["rm", "-rf", str(TEMP_DIR)], check=True)
    
    print(f"\n✅ 完成!")
    print(f"   成功:{len(results)}/58")
Confidence
98% confidence
Finding
`TEMP_DIR` is derived from `WORKSPACE`, and then passed to a recursive deletion command. If an attacker controls `WORKSPACE`, they can influence what directory gets removed, potentially causing destructive data loss beyond temporary files.

Tainted flow: 'summary_path' from os.getenv (line 227, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
summary += f"| {r['drawing_no']} | {r['model_no']} | {r['product']} |\n"
    
    summary_path = KB_DIR / "00-599 汇总.md"
    with open(summary_path, 'w', encoding='utf-8') as f:
        f.write(summary)
    
    subprocess.run(["rm", "-rf", str(TEMP_DIR)], check=True)
Confidence
90% confidence
Finding
`summary_path` is based on `KB_DIR`, which in turn depends on environment-controlled `WORKSPACE`. That allows writes to attacker-chosen filesystem locations, enabling unauthorized file creation or overwrite if the process runs with sufficient privileges.

Tainted flow: 'cmd' from os.getenv (line 63, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
"--stdout", "-f", "json"
    ]
    
    result = subprocess.run(cmd, capture_output=True, text=True)
    
    try:
        # 解析 JSON(跳过 stderr)
Confidence
93% confidence
Finding
Here the subprocess target path is built from `WORKSPACE`, which comes from the environment, and is then executed as `python3 <script_path>`. If an attacker can control `WORKSPACE`, they may redirect execution to an attacker-controlled script path and achieve arbitrary code execution in the context of the user running this tool.

Tainted flow: 'req' from os.environ.get (line 381, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
},
    )

    with urllib.request.urlopen(req, timeout=120) as resp:
        result = json.loads(resp.read().decode("utf-8"))

    text = result["choices"][0]["message"]["content"]
Confidence
98% confidence
Finding
The script sends extracted drawing images to an external OpenRouter endpoint, authenticated by a secret pulled from the environment or a built-in fallback key. This creates a real confidentiality risk because potentially sensitive engineering drawings are exfiltrated to a third-party service, and the environment-derived credential is used to authorize that transfer.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises and documents capabilities that require file access, shell execution, network access, and likely environment-variable use, but it does not declare permissions. This creates a transparency and policy-enforcement gap: users and platforms cannot accurately assess or constrain what the skill may do before execution.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding
The documented behavior extends beyond a local PDF extractor into batch Drive operations, knowledge-base writes, aggregate document generation, and external Vision/API usage. That mismatch increases the risk of unexpected data exfiltration, broader filesystem modification, and overbroad automation in contexts where the user expects only local document parsing.

Context-Inappropriate Capability

Medium
Confidence
71% confidence
Finding
Excel updating is a side-effecting document-manipulation capability that exceeds a narrow extractor description and can change business records. If users or reviewers believe the skill is read-only, they may grant it access or run it without understanding that it can alter spreadsheets, creating integrity and change-control risk.

Context-Inappropriate Capability

Low
Confidence
95% confidence
Finding
Destructive directory deletion is not justified by the extraction-focused purpose and is dangerous because it operates recursively on a configurable path. In this context, unnecessary destructive capability materially increases risk: a bad temp path, compromised environment, or operator mistake can wipe unrelated data.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The code uploads base64-encoded page images of product drawings to OpenRouter for analysis, which is inconsistent with a tool presented as a document extractor and materially expands the data exposure boundary. In the context of engineering drawings, this is especially sensitive because designs, BOMs, and manufacturing details may be proprietary or export-controlled.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The implementation contradicts its 'fallback only' description by still converting PDFs to images and invoking the Vision path whenever vision is enabled, even if text extraction already worked. That misrepresentation increases the chance of unexpected data exfiltration because users may believe remote processing occurs only on failure cases.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The script silently falls back to a hard-coded OpenRouter API key when no environment variable is present. Embedding a usable credential in source code is a serious secret-management failure that can enable unauthorized use, abuse of the account, and hidden network egress without operator awareness.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The script base64-encodes full PDF page images and sends them to external Vision APIs, which can disclose proprietary engineering drawings, BOMs, dimensions, and customer data to third parties. In the context of a product drawing extractor for Farreach materials, this is especially sensitive because drawings commonly contain confidential manufacturing and commercial information.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The code searches a user home-directory config file for API credentials unrelated to the immediate CLI arguments, expanding the skill's access to local secrets beyond what users would reasonably expect from a document extractor. This creates unnecessary secret exposure risk and couples execution to ambient credentials that may belong to other tools or contexts.

Context-Inappropriate Capability

High
Confidence
100% confidence
Finding
The script contains a hardcoded OpenRouter API key fallback, enabling outbound access even when the user has not configured credentials. This is a severe supply-chain and data-exfiltration risk because it silently routes sensitive drawing images to an external service under a baked-in account, bypassing normal user control and audit expectations.

Static analysis

No suspicious patterns detected.