Back to skill

Security audit

专利检索 · PatentMax

Security checks for vulnerabilities and agentic risk

Overview

This is a real patent-search skill, but it needs Review because it sends sensitive patent queries and bearer tokens to an externally configurable service and can run small paid operations without a hard prior approval gate.

Install only if you are comfortable sending patent searches, technical descriptions, and any configured PatentMax bearer token to PatentMax. Before use, verify PATENTMAX_BASE_URL is unset or points only to the intended service, avoid putting live keys in shared logs or synced configs, and require explicit approval for any paid operation rather than relying on the skill's silent ≤¥5 rule. Do not use it for confidential unpublished invention details unless the user has approved third-party processing.

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

Warning
Location
scripts/patentmax_client.py:914
Finding

Metered API Operations Can Execute Without an Enforced User-Approved Spending Limit

Content
View full analysis

Vulnerability Details

File Location: scripts/patentmax_client.py:789-790, 809, 914-920, 1265-1268; related workflow instructions at SKILL.md:143,352
Vulnerability Type: Missing authorization control for financially consequential operations
Risk Level: Medium

Relevant Code

python
# No configured budget means monetary spending is not blocked.
# The original source comment at lines 789-790 documents this behavior.

BILLED_COMMANDS = (
    "search", "stats", "company", "brief",
    "similar", "citation", "figure"
)

def enforce_budget(args):
    enforce_search_budget(args)
    session = _load_session()
    if not session or args.command not in BILLED_COMMANDS:
        return
    limit = float(session.get("limit", 0))
    spent = float(session.get("spent", 0))
    need = estimate_cost(args)
    if limit <= 0 or spent + need <= limit + 1e-9:
        return
python
enforce_budget(args)
if args.command in BILLED_COMMANDS:
    _task_id = ensure_task()
result = args.func(args)
if args.command in BILLED_COMMANDS:
    record_usage(args.command)

The associated Skill workflow is internally inconsistent:

  • SKILL.md:143 says the depth and estimated cost should be shown before paid searching begins.
  • SKILL.md:352 instructs the Agent to execute estimated costs of up to ¥5 silently and report the charge afterward.

Technical Analysis

The client identifies financially consequential operations through BILLED_COMMANDS, but does not require a user-approved budget before executing them.

enforce_budget() returns without blocking when:

  1. No active budget session exists; or
  2. The session has a limit of zero or less.

Execution then continues directly to args.func(args), which can issue an authenticated, metered API request. The budget session subsequently created by ensure_task() has no monetary limit by default. Therefore, the control records usage after execution but does not establish prior financial authorization.

...[truncated 2457 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require prior authorization for every billable command. Reject execution unless the current task has an explicitly initialized spending limit or a verifiable approval token.

  2. Use fail-closed budget logic. Replace the permissive behavior for missing or non-positive limits with an error that identifies the command and estimated maximum charge:

python
if args.command in BILLED_COMMANDS:
    if not session or float(session.get("limit", 0)) <= 0:
        die(
            "This operation is billable and requires an approved task budget.",
            exit_code=3
        )
  1. Bind approval to the current task. Store the approved amount, authorized command classes, account context, and task identifier together. Do not reuse approval across unrelated or expired tasks.

  2. Enforce the cap before network access. Reserve the estimated charge atomically before calling the API, then reconcile it against the authoritative charge returned by the service. Prevent concurrent processes from independently passing the same remaining-budget check.

  3. Cover all billable operations. Add operation-count or monetary controls for stats, company, brief, similar, citation, and figure, not only search.

  4. Remove the silent-spending instruction. Make SKILL.md consistently require disclosure and explicit approval before any operation that can consume paid balance. Free-quota execution may be handled separately only when the client can authoritatively verify that the request will not incur a charge.

  5. Require renewed approval when scope changes. Additional rounds, higher-cost operations, or execution beyond the approved amount should stop and request a new authorization rather than silently continuing.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (37)

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

Critical
Category
Data Flow
Confidence
94% confidence
Finding

The client builds outbound requests using a base URL taken from the PATENTMAX_BASE_URL environment variable and then automatically sends data to that host, including trial-key registration data or an Authorization bearer token in other paths. If an attacker can influence the environment, they can redirect traffic to an attacker-controlled endpoint and capture credentials or sensitive patent queries, making this a real SSRF/credential-exfiltration risk.

Content

Scanner excerpt · scripts/patentmax_client.py (reported line 118)May include surrounding context.

python
req.add_header("Content-Type", "application/json")
    req.add_header("Accept", "application/json")
    try:
        with urllib.request.urlopen(req, timeout=30) as response:
            payload = json.loads(response.read().decode("utf-8"))
    except urllib.error.HTTPError as exc:
        message = _server_message(exc.read().decode("utf-8", "replace"))

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

Critical
Category
Data Flow
Confidence
98% confidence
Finding

The main request path uses PATENTMAX_BASE_URL to construct requests and always attaches the PATENTMAX_API_KEY as a Bearer token before calling urlopen. An attacker who controls this environment variable can force the tool to transmit the API key, user queries, and patent identifiers to an attacker-controlled server, directly causing secret exfiltration and unauthorized use of the account.

Content

Scanner excerpt · scripts/patentmax_client.py (reported line 318)May include surrounding context.

python
req.add_header(key, value)

    try:
        with urllib.request.urlopen(req, timeout=TIMEOUT) as response:
            payload = response.read()
            # 服务端每个响应都回本次实扣和扣完后的余额。记下来,供 _spent/_balance 输出。
            # 拿服务端的真值,而不是在本地累加估价:跨进程累加迟早算岔,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

该安装文档从标题开始即完全以中文编写,未提供其他语言版本、语言选择方式,或说明这是仅面向中文用户/地区的技能。根据规则,强制特定语言而无用户 opt-in 或明确、合理的地域性说明,属于自然语言层面的组织政策风险。

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The instructions tell users to set a production API key and even print part of it for verification, but do not warn about shell history, shared terminals, logs, screenshots, or secure secret storage. In agent and CLI environments, this increases the chance of accidental credential exposure and subsequent unauthorized API use or billing abuse.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The documentation embeds a bearer token directly in an MCP configuration example header, which can normalize storing secrets in plaintext config files. In agent ecosystems, such config files are often synced, logged, or shared, creating a practical risk of credential leakage and unauthorized API consumption.

Content

Scanner excerpt · INSTALL.md (reported line 107)May include surrounding context.

md
{
  "mcpServers": {
    "patentmax": {
      "url": "https://api.ip930.com/api/mcp",
      "headers": { "Authorization": "Bearer pm_live_你的密钥" }
    }
  }

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The entire skill description is presented only in Chinese, and there is no indication that users may choose another language or that the skill is intentionally restricted to a Chinese-speaking or China-specific audience. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

The README states that the script will automatically claim a free trial on first run and store credentials or trial state locally under ~/.patentmax/, which implies automatic outbound communication to a third-party service. In an agent setting, this can cause unreviewed data transmission, account creation/activation side effects, and silent credential material being written to disk without explicit user consent.

Content

Scanner excerpt · README.md (reported line 102)May include surrounding context.

不需要密钥,装上就能用。 第一次运行时脚本自动领取一份免费试用:累计 ¥40 额度、30 天有效,存在本机 ~/.patentmax/。

试用用完后,到 api.ip930.com/features/api-platform 注册(再送 ¥50),创建一个密钥,设成环境变量,设了就不再用试用:

bash
export PATENTMAX_API_KEY="pm_live_你的密钥"

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The README encourages direct integration with a remote MCP/HTTP endpoint and suggests use from any Bash-capable AI client, increasing the chance that prompts, patent queries, metadata, or access tokens are transmitted to an external service. In a skill context, this is more dangerous because users may invoke it through autonomous agents that forward sensitive research, internal invention details, or OAuth-authorized context to a third party.

Content

Scanner excerpt · README.md (reported line 110)May include surrounding context.

md
完事了。没有配置文件要改,不用重启客户端——**任何能跑 Bash 的 AI 客户端都能用**。

> 同一套数据也提供 **MCP 接入**:端点 `https://api.ip930.com/api/mcp`,Streamable HTTP,支持 OAuth 2.1 一键授权,可直接接进 Claude、Cursor、扣子等兼容 Model Context Protocol 的客户端。这个 Skill 走 HTTP 接口是为了不挑客户端,两条路都通。

`scripts/patentmax_client.py` 只用 Python 标准库,不需要 `pip install`。环境里连 Python 都没有的话,直接 curl 也行,接口清单在 [references/api-reference.md](references/api-reference.md)。

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The invocation description includes many broad natural-language triggers such as '找专利', '技术趋势分布', and company portfolio questions, which can cause the skill to activate in loosely related contexts. Because the skill can send user-supplied technical content to an external service and may automatically claim a trial, over-broad triggering increases the chance of unintended data transmission and unintended spending.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The argument hint is presented only in Chinese ('[专利号 / 检索式 / 企业名称]'), and the document overwhelmingly instructs usage in Chinese without offering a language choice. This can amount to a locale/language constraint that is not explicitly justified as mandatory or offered as an opt-in.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
93% confidence
Finding

The skill directs the agent to transmit queries and possibly sensitive technical方案、配方、参数 or commercial details to a third-party API endpoint and even auto-claim a free trial on first use. In context, this is more sensitive because the skill itself warns that confidential technical content may be sent to the service, so accidental use can leak proprietary information and create unexpected external account/billing side effects.

Content

Scanner excerpt · SKILL.md (reported line 659)May include surrounding context.

试用用完、过期,或想用其他功能(查新、交底书等)时,命令会返回带 "free_trial": true 的错误,message 里写着下一步怎么办(注册 PatentMax 再送 ¥50 体验额度),原样转告用户,不要自己换写法重试。

用户有自己的密钥时用环境变量传,避免写进命令历史;设了就一律用它,不会领试用。密钥在 api.ip930.com 控制台创建:

bash
export PATENTMAX_API_KEY="pm_live_你的密钥"

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Earlier sections repeatedly define the skill boundary as patent retrieval via the PatentMax service and explicitly say several adjacent tasks are 'not in scope'. However, this section directs the agent to use browsing tools to query CNIPA/WIPO/EPO/USPTO and to supplement with papers, standards, product manuals, and conference materials. That expands the operational intent beyond the stated scope and directly conflicts with the narrower documentation elsewhere in the file.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

With no manifest permissions baseline beyond allowed tools, the main stated purpose in the file is patent search through PatentMax. Directing the agent to query official registries and search papers, standards, product manuals, and conference materials introduces a broader open-web research capability not obviously required for a PatentMax patent-search skill.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file is written entirely in Chinese and does not indicate that another language version is available or that Chinese is required for a region-specific compliance reason. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The entire skill guidance is written as mandatory instructions in Chinese and includes language-specific operational advice such as switching between Chinese and English terms. There is no indication that the user can choose another language or that the skill is intentionally restricted to a Chinese-speaking or China-specific compliance context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring explicitly states that errors and human-readable prompts are returned in Chinese, and the CLI help/messages throughout the file are also Chinese-only. This is a natural-language locale policy issue because the skill imposes a specific language on users without opt-in or an alternative locale path.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · INSTALL.md (reported line 9)May include surrounding context.

md
# 设了 PATENTMAX_API_KEY 就一律用它,不会去领试用。
TRIAL_SOURCE = "patent-search-cn"
TRIAL_GROUP = "patent-search"
TRIAL_REGISTER_URL = "https://api.ip930.com/features/api-platform"
KEY_FROM_TRIAL = False

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · INSTALL.md (reported line 73)May include surrounding context.

md
# 设了 PATENTMAX_API_KEY 就一律用它,不会去领试用。
TRIAL_SOURCE = "patent-search-cn"
TRIAL_GROUP = "patent-search"
TRIAL_REGISTER_URL = "https://api.ip930.com/features/api-platform"
KEY_FROM_TRIAL = False

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · INSTALL.md (reported line 81)May include surrounding context.

md
# 设了 PATENTMAX_API_KEY 就一律用它,不会去领试用。
TRIAL_SOURCE = "patent-search-cn"
TRIAL_GROUP = "patent-search"
TRIAL_REGISTER_URL = "https://api.ip930.com/features/api-platform"
KEY_FROM_TRIAL = False

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · INSTALL.md (reported line 90)May include surrounding context.

md
# 设了 PATENTMAX_API_KEY 就一律用它,不会去领试用。
TRIAL_SOURCE = "patent-search-cn"
TRIAL_GROUP = "patent-search"
TRIAL_REGISTER_URL = "https://api.ip930.com/features/api-platform"
KEY_FROM_TRIAL = False

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · INSTALL.md (reported line 101)May include surrounding context.

md
# 设了 PATENTMAX_API_KEY 就一律用它,不会去领试用。
TRIAL_SOURCE = "patent-search-cn"
TRIAL_GROUP = "patent-search"
TRIAL_REGISTER_URL = "https://api.ip930.com/features/api-platform"
KEY_FROM_TRIAL = False

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · INSTALL.md (reported line 136)May include surrounding context.

md
# 设了 PATENTMAX_API_KEY 就一律用它,不会去领试用。
TRIAL_SOURCE = "patent-search-cn"
TRIAL_GROUP = "patent-search"
TRIAL_REGISTER_URL = "https://api.ip930.com/features/api-platform"
KEY_FROM_TRIAL = False

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api-reference.md (reported line 16)May include surrounding context.

md
# 设了 PATENTMAX_API_KEY 就一律用它,不会去领试用。
TRIAL_SOURCE = "patent-search-cn"
TRIAL_GROUP = "patent-search"
TRIAL_REGISTER_URL = "https://api.ip930.com/features/api-platform"
KEY_FROM_TRIAL = False

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api-reference.md (reported line 48)May include surrounding context.

md
# 设了 PATENTMAX_API_KEY 就一律用它,不会去领试用。
TRIAL_SOURCE = "patent-search-cn"
TRIAL_GROUP = "patent-search"
TRIAL_REGISTER_URL = "https://api.ip930.com/features/api-platform"
KEY_FROM_TRIAL = False

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api-reference.md (reported line 73)May include surrounding context.

md
# 设了 PATENTMAX_API_KEY 就一律用它,不会去领试用。
TRIAL_SOURCE = "patent-search-cn"
TRIAL_GROUP = "patent-search"
TRIAL_REGISTER_URL = "https://api.ip930.com/features/api-platform"
KEY_FROM_TRIAL = False

Static analysis

No suspicious patterns detected.