Back to skill

Security audit

patent-download

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed patent-downloading tool, but it needs review because its wrapper auto-installs unpinned packages and one download path can write files outside the intended output folder from crafted input.

Install only if you are comfortable with a local script that can access patent-platform credentials, make network requests, launch browser automation, and write files. Prefer running python cli.py directly after manually installing reviewed, pinned dependencies in a virtual environment; avoid the auto-install wrapper, and only pass normal patent identifiers and trusted output directories.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T08 · Insecure Dependencies

Warning
Location
scripts/patent-download.sh:15
Finding

Automatic Installation of Unpinned Third-Party Dependencies

Content
View full analysis

Vulnerability Details

File Location: scripts/patent-download.sh:15-19, 25-30; scripts/requirements.txt:1-8
Vulnerability Type: Uncontrolled third-party dependency installation
Risk Level: Medium

Vulnerable Code

bash
if [ "$1" = "google" ]; then
    # Check patent-downloader
    if ! python3 -c "from patent_downloader import PatentDownloader" 2>/dev/null; then
        echo "Installing Google Patents dependency..."
        pip install patent-downloader
    fi
    # Run the unified entry point
    python3 cli.py "$@"
    exit $?
fi

# Legacy path: check Playwright
if ! python3 -c "import playwright" 2>/dev/null; then
    echo "Installing browser automation dependencies..."
    pip install -r requirements.txt
    playwright install chromium
fi

The referenced requirements file contains unconstrained dependencies:

text
# Google Patents SDK
patent-downloader

# Browser automation
playwright

# HTTP requests
requests

Technical Analysis

The wrapper automatically invokes package managers when dependencies are absent. None of the Python packages are pinned to exact versions, and no package hashes or lockfile are provided. The Chromium browser binary installed by Playwright is similarly selected at installation time.

Python package installation can execute package build and installation logic. Consequently, the effective code executed by the Skill can change after the Skill itself has been reviewed. A compromised package release, compromised package index, dependency confusion event, or malicious transitive dependency could execute arbitrary code with the privileges of the user invoking the wrapper.

The automatic installation and associated supply-chain risk are disclosed in SKILL.md, which reduces the risk of hidden behavior but does not provide a technical security boundary.

Attack Path

  1. An attacker compromises an upstream package, its maint ...[truncated 1117 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove all automatic dependency installation from the runtime wrapper.
  2. Require a separate, explicit, user-approved setup command.
  3. Pin every direct and transitive Python dependency to an exact reviewed version.
  4. Use a hash-locked requirements file, such as one generated with pip-compile --generate-hashes, and install with pip install --require-hashes.
  5. Install dependencies in a dedicated virtual environment rather than the user's global Python environment.
  6. Pin and verify the Playwright and Chromium versions.
  7. Run dependency vulnerability and provenance checks in CI.
  8. Where practical, sandbox the browser and downloader with restricted filesystem, environment, and network access.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download.py:176
Finding

User-Controlled Patent Number Can Escape the Output Directory

Content
View full analysis

Vulnerability Details

File Location: scripts/download.py:176-178, 193-195, 215-217, 227-228
Vulnerability Type: Path traversal and unintended file overwrite
Risk Level: Medium

Vulnerable Code

python
filename = f"{patent_number}_{title}.pdf"
filepath = os.path.join(output_dir, filename)
download.save_as(filepath)

The same unsafe construction is repeated for another download path:

python
filename = f"{patent_number}_{title}.pdf"
filepath = os.path.join(output_dir, filename)
download.save_as(filepath)

It is also used when writing a PDF response directly:

python
filename = f"{patent_number}_{title}.pdf"
filepath = os.path.join(output_dir, filename)
with open(filepath, "wb") as f:
    f.write(response.content)

Finally, the debug page uses the unsanitized value:

python
debug_file = os.path.join(output_dir, f"{patent_number}_debug.html")
with open(debug_file, "w", encoding="utf-8") as f:
    f.write(page.content())

Technical Analysis

patent_number originates directly from a positional command-line argument. Although the remotely obtained patent title is sanitized, the patent number is not validated or reduced to a safe filename.

Values containing .., path separators, or an absolute path can alter the final destination produced by os.path.join. In particular, when the constructed filename is absolute, os.path.join discards output_dir. Traversal components can also escape the output directory where the referenced intermediate directories exist.

The code does not resolve the final path and verify that it remains beneath the intended output directory. It also writes files without an exclusive-create or overwrite-protection policy.

Attack Path

  1. An attacker supplies or persuades an agent to process a crafted patent-number argument containing path components.
  2. The value reaches download_patent() without strict patent-numb ...[truncated 1079 chars]
Remediation
View remediation

Remediation Suggestions

  1. Validate patent identifiers against a strict allowlist before any network or filesystem operation. Permit only the documented letters, digits, periods, and hyphens.
  2. Explicitly reject /, \, null bytes, absolute paths, drive prefixes, and .. path components.
  3. Convert the identifier to a safe basename rather than using raw input.
  4. Resolve the output directory and destination with Path.resolve(), then verify that the destination is a descendant of the resolved output directory.
  5. Apply the same validation to PDF and debug filenames.
  6. Avoid silently overwriting existing files; use an exclusive-create policy or request confirmation.
  7. Add tests for absolute paths, nested traversal, Windows separators, drive paths, and encoded separator variants.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download.py:209
Finding

Patent Queries and Downloaded Files Are Transferred over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/download.py:72, 155, 209-218; scripts/platforms/epub.py:25, 57
Vulnerability Type: Cleartext network communication and unverified downloaded content
Risk Level: Medium

Vulnerable Code

The initial browser navigation uses plaintext HTTP:

python
page.goto("http://epub.cnipa.gov.cn/Index", timeout=30000)

A later navigation also uses plaintext HTTP:

python
page.goto(f"http://epub.cnipa.gov.cn/Dxb/IndexQuery?patentCode=CN{patent_code}")

PDF URLs are constructed and downloaded without transport security or content validation:

python
if not pdf_url.startswith("http"):
    pdf_url = "http://epub.cnipa.gov.cn" + pdf_url

# Download using requests
import requests
response = requests.get(pdf_url, timeout=30)
if response.status_code == 200:
    filename = f"{patent_number}_{title}.pdf"
    filepath = os.path.join(output_dir, filename)
    with open(filepath, "wb") as f:
        f.write(response.content)

The platform module also declares the plaintext endpoint:

python
CONFIG = {
    "base_url": "http://epub.cnipa.gov.cn",
}
python
BASE_URL = "http://epub.cnipa.gov.cn"

Technical Analysis

HTTP provides neither server authentication nor transport integrity. Patent identifiers, browsing activity, HTML responses, and downloaded PDF bytes can be observed or modified by an attacker positioned on the network path.

The direct download path accepts any HTTP 200 response and writes it with a .pdf extension. It does not verify the final response origin, reject redirects to unrelated hosts, validate Content-Type, check the PDF magic header, enforce a size limit, or verify a trusted digest or signature.

Because the resulting file may later be opened in a PDF viewer, saving network-modified content creates a secondary client-side risk in addition to confidentiality and integrity concerns.

...[truncated 1090 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace all CNIPA HTTP URLs with verified HTTPS endpoints.
  2. Fail closed if HTTPS is unavailable rather than silently falling back to HTTP.
  3. Restrict redirects and final response URLs to an explicit allowlist of trusted HTTPS hosts.
  4. Validate the response status, Content-Type, content length, and PDF magic header before writing.
  5. Apply conservative download size and timeout limits.
  6. Where the publisher provides checksums or signatures, verify them before treating the file as trusted.
  7. Write downloads to a temporary file, validate them, and atomically move them into the destination only after successful verification.
  8. Clearly mark legacy plaintext-only integrations as disabled if secure transport cannot be supported.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (54)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The code is clearly related to patent PDF downloading, so the high-level domain matches. However, the declared description materially overstates the implementation. The supplied code only implements a CNIPA/epub downloader and does not show multi-platform behavior or Google Patents support. It accepts multiple patent numbers from the CLI, so some batch processing exists, but this is just sequential downloading rather than the broader 'batch export patent files' capability described. It also does not meaningfully implement patent metadata querying beyond checking search results and scraping a title for the filename. Finally, the claimed automatic handling of application and publication number formats is not evident in the code. Therefore, the description does not accurately represent the actual behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

代码的主功能与声明存在实质性偏差。虽然命令行支持传入多个专利号并逐个执行搜索/点击,因此勉强可算批量处理入口,但核心承诺“下载专利全文 PDF”和“批量导出专利文件”并未实现。download_pdf 方法实际上只是在网页中尝试点击结果、点击“专利单行本”与“打包下载/查看PDF”按钮,最后明确打印“本模块未保存文件”并返回 None。此外,声明强调多平台支持和 Google Patents 优先,但当前代码块只实现 epub.cnipa.gov.cn 平台;也没有看到申请号/公告号格式自动处理逻辑。因此,该描述明显高于实际代码能力,构成不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

代码与声明部分重合:它确实用于专利 PDF 下载和专利信息查询,也处理专利号格式。但声明中的几个关键能力在该代码块中未实现。首先,代码明确只是 scripts/platforms/google_patents.py 的单个平台实现,没有多平台逻辑。其次,核心函数和 CLI 都是单个 patent 参数,没有批量处理或批量导出实现。再次,注释和声明多次提到申请号“自动转换/自动查公告号”,但 _try_fetch() 在遇到申请号时只是打印提示,说明 Google Patents 不能直接用申请号查询,并要求用户自行去 PatentGuru/度衍查询公告号,因此这与“自动处理申请号和公告号格式”的表述存在实质偏差。整体来看,代码是声明功能集合中的一个子模块,且缺少若干被强调的能力,因此应判定为描述与实际行为不完全一致。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

该代码块与声明存在明显描述-行为不一致。代码文件本身在注释和实现中都明确说明“PDF 下载未实现”,实际只完成了登录、搜索和尝试点击详情页,最后还提示用户改用 Google Patents。虽然它接受多个专利号参数并逐个循环处理,表面上有“批量”入口,但并没有实际下载或导出任何专利文件,因此不能支持声明中的核心用途“批量下载 PDF/导出文件”。此外,声明强调多平台与号码格式自动处理,而本代码仅面向 gpic 单平台,且没有任何申请号/公告号格式处理逻辑。没有发现超出声明范围的危险性未声明能力;问题主要是声明夸大了实际实现程度和支持范围。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

声明描述的是一个面向多平台的专利 PDF 批量下载/查询/导出工具,但该代码片段的实际功能明显更窄且不同。代码只针对 PatentStar API,包含登录、搜索和批量导出接口,其中 export 调用的是 BulkDownloadExcel 并将响应保存为 .xlsx 文件,说明其核心导出行为是 Excel 而非 PDF。虽然存在 search 方法,但主程序并未调用查询流程;同时代码中没有任何 Google Patents、多平台路由、或申请号/公告号格式规范化处理逻辑。因而该代码与声明的核心用途存在实质性不一致。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

代码没有表现出危险或额外未声明能力,主要问题是声明的核心功能远超出实际实现。文件头和 download_pdf 方法都明确说明 PDF 下载尚未实现,且详情页验证码未处理、未保存任何文件。实际行为局限于登录 PatentStar、执行搜索、尝试点击结果详情。因此,声明与行为存在明显的功能性不匹配,属于夸大描述/未实现核心能力的情况。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

这是明显的描述与行为不符。代码注释和实现都直接说明该模块“仅完成搜索+进入详情,未实现真正的 PDF 保存”,因此与“专利 PDF 批量下载工具”的核心用途不一致。虽然代码确实具备登录、检索、逐个处理多个专利号的能力,和“查询专利信息”部分有一定相关性,但其主要宣称能力——PDF 下载、批量导出、多平台支持、号码格式自动处理——在该代码块中均未实际实现。未发现额外的、未声明的敏感能力;问题主要是声明显著夸大了实际功能。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

该代码块的实际用途是对度衍专利网站进行浏览器自动化操作,包含登录、搜索和尝试点击 PDF 下载按钮。其核心功能仍处于不完整状态:API 方法是未实现桩,浏览器下载流程也明确说明“未监听 download 事件保存文件”,因此不能视为真正实现了 PDF 下载。与声明相比,代码缺少多平台支持、Google Patents 优先逻辑、号码格式自动处理、专利信息查询输出以及批量导出能力。虽然支持一次输入多个专利号进行循环处理,但这不足以等同于“批量导出专利文件”。因此,声明与该代码块的实际行为存在明显且实质性的能力不匹配。

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/accounts-setup.md (reported line 53)May include surrounding context.

md
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/accounts-setup.md (reported line 56)May include surrounding context.

md
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/cli.py (reported line 70)May include surrounding context.

python
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/platforms/_creds.py (reported line 9)May include surrounding context.

python
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/platforms/_creds.py (reported line 10)May include surrounding context.

python
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/platforms/_creds.py (reported line 12)May include surrounding context.

python
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/platforms/_creds.py (reported line 47)May include surrounding context.

python
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/platforms/_creds.py (reported line 69)May include surrounding context.

python
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/platforms/_creds.py (reported line 71)May include surrounding context.

python
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/platforms/_creds.py (reported line 76)May include surrounding context.

python
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/platforms/_creds.py (reported line 97)May include surrounding context.

python
PATENT_<PLATFORM>_PASSWORD
例如 uyanip → PATENT_UYANIP_USERNAME / PATENT_UYANIP_PASSWORD

可在 config/.env 文件中配置(本地,不入库),见 config/.env.example;
也可直接 export。环境变量优先于 .env 文件。

无额外依赖:.env 由本模块手动解析。读不到返回空字符串,

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/platforms/_creds.py (reported line 21)May include surrounding context.

python
ENV_PREFIX = "PATENT_"
_ENV_PATH = os.path.join(
    os.path.dirname(os.path.abspath(__file__)),
    "..", "..", "config", ".env",
)

_loaded = False

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

Line L003 states in Chinese that the file records user-visible changes, and the entire changelog is written in Chinese with no indication that other languages are available. This can violate language/locale policy when a skill imposes a specific language on users without opt-in or documented regional limitation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises and documents capabilities to read environment variables, write files, access the network, and invoke shell commands, including an auto-install wrapper that runs pip and downloads browser binaries, but the manifest does not declare any tool scope such as permissions or allowed-tools. This creates a governance and review gap: operators cannot easily constrain or audit what the skill is allowed to do, increasing the chance of unintended command execution, dependency installation, or data access.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest description and primary usage guidance are entirely in Chinese, including the activation/use conditions, with no indication that users may choose another language. This can violate language/locale policy when a skill imposes a specific language without opt-in or documented regional justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This markdown file presents all user-facing instructions, examples, and explanations exclusively in Chinese, including the quick-start and troubleshooting sections. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The file's natural-language interface strings, help text, and console output are presented in Chinese throughout, with no indication that language selection is optional or that the tool is intentionally limited to a Chinese-speaking audience. Under the policy rule, forcing a specific language without user opt-in is a locale/language policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.