Back to skill

Security audit

城市专利画像

Security checks for vulnerabilities and agentic risk

Overview

The patent-reporting workflow is legitimate, but weaknesses in account-key protection and error handling warrant review before use.

Prefer the free trial until credential storage, redirect protection, and cache-path handling are corrected. Do not paste paid account keys into chat. Search terms go to PatentMax, so obtain approval before submitting confidential invention details. Set a spending cap, check charges after timeouts, and verify unexpectedly empty statistics.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • 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 (30)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/patentmax_client.py (reported line 142)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 333, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
94% confidence
Finding

Sending the PatentMax key to its intended API is legitimate, but the client attaches that key to any configured BASE_URL without enforcing HTTPS or a trusted destination. Default urllib redirect handling can also forward this explicitly added Authorization header to a different origin, allowing endpoint misconfiguration or a malicious redirect to expose a saved paid-account key.

Content

Scanner excerpt · scripts/patentmax_client.py (reported line 344)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 输出。
            # 拿服务端的真值,而不是在本地累加估价:跨进程累加迟早算岔,

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The supplied command exposes a credential prefix rather than retrieving or analyzing patent data. Although using an API key could support the declared reporting purpose, printing its contents is an undeclared disclosure and is not necessary for that purpose. The snippet does not show external transmission or disclosure of the full key.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

Although patent retrieval can support regional analysis, this chunk explicitly implements a solution-centered similarity workflow. It does not select a city or district, analyze regional patent holdings, or calculate the declared profile metrics. Its demonstrated purpose is therefore materially different from the declared regional-analysis purpose. No additional filesystem access or other undeclared side effects are established by the supplied commands.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

The supplied chunk targets one fixed patent and contains no geographic filtering, regional aggregation, trend analysis, organization ranking, or report generation. Although individual patent retrieval could support a broader analytical workflow, this chunk provides no connection between the claims lookup and the declared regional profiling purpose. The API authentication itself is a normal implementation detail, not a separate mismatch.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
86% confidence
Finding

The supplied command performs a similarity search centered on an individual patent. It contains no geographic scope, regional aggregation, trend analysis, or report generation. Although patent searches can support regional profiling, this chunk does not establish such a connection and instead implements a distinct patent-similarity workflow. The client implementation is not supplied, so no additional behavior or resource access can be inferred.

Content

No source excerpt is available for this finding.

Code capability 'env' detected in scripts/patentmax_client.py but not covered by declared permissions.

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding

The skill uses 'env' capability that is not covered by the declared 'allowed-tools' preapproval. Review the host runtime's actual enforcement policy; runtime permissions are unknown unless separately verified, and this declaration alone does not establish a permission ceiling.

Content

No source excerpt is available for this finding.

Code capability 'network' detected in scripts/patentmax_client.py but not covered by declared permissions.

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding

The skill uses 'network' capability that is not covered by the declared 'allowed-tools' preapproval. Review the host runtime's actual enforcement policy; runtime permissions are unknown unless separately verified, and this declaration alone does not establish a permission ceiling.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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.

bash
curl -s -H "Authorization: Bearer $PATENTMAX_API_KEY" \
  "https://api.ip930.com/api/patent?pn=CN109761224A"

服务端自己完成内部寻址,这些前置调用不进用户账单。

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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.

服务端直接返回上次的结果、不再扣费;同一个键换了参数会被拒(400);上一次还在处理中返回 409。

bash
curl -s -H "Authorization: Bearer $PATENTMAX_API_KEY" -H "Idempotency-Key: task42-search-1"   "https://api.ip930.com/api/search?q=%E6%B5%B8%E6%B2%A1%E5%BC%8F%E6%B6%B2%E5%86%B7&ds=cn&size=20"

网络超时、不确定上一次有没有成功时,用同一个键重发,不要换键。

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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.

curl -s -H "Authorization: Bearer $PATENTMAX_API_KEY"
--data-urlencode 'q=(固态电池 OR 全固态电池) AND 电解质'
--data-urlencode 'ds=all' --data-urlencode 'size=20'
-G "https://api.ip930.com/api/search"

text

> 检索式里有中文和括号,一定用 `--data-urlencode -G`,别手工拼 URL。

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 89)May include surrounding context.

bash
curl -s -H "Authorization: Bearer $PATENTMAX_API_KEY" \
  "https://api.ip930.com/api/patent?pn=CN109761224A"

某一块上游取不到时,该字段为 null 并在 unavailable 里列出,其余照常返回;

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 114)May include surrounding context.

bash
curl -s -H "Authorization: Bearer $PATENTMAX_API_KEY" \
  "https://api.ip930.com/api/claims?pn=CN109761224A"

只要同时需要两块以上,就用 /api/patent——它一口价,拆开单买反而贵。

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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/faq.md (reported line 35)May include surrounding context.

md
- **密钥复制不全。** 前后有没有多余空格、有没有漏掉尾部字符
- **少了 `Bearer ` 前缀。** 用 curl 时 header 必须是 `Authorization: Bearer pm_live_xxx`,只写密钥不行
- **密钥被撤销了。** 到 [控制台](https://api.ip930.com/features/api-platform)看状态

> 还有个容易踩的:如果请求里带了 `Authorization` 头,URL 上的 `?apikey=` 就不会被读取。两种方式选一种,别混用——带了一个格式错误的 header,正确的 URL 参数也会被忽略。

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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/faq.md (reported line 41)May include surrounding context.

md
## 402 余额不足

到[控制台](https://api.ip930.com/features/api-platform)充值。

新账户的体验额度分两笔:注册送 ¥10,第一次调用成功后再送 ¥40。如果第二笔一直没到,确认第一次调用确实返回了 200——失败的调用不算。

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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/faq.md (reported line 119)May include surrounding context.

md
## 花了多少钱

脚本每次返回都带 `_spent`(本次实扣)和 `_balance`(余额),**这两个数来自服务端,是真值**。
准确的流水到[控制台](https://api.ip930.com/features/api-platform)查。

| 调用 | 单价 |
| --- | --- |

The workflow directs searches based on the user's technical invention without warning that query details are sent to the patent-search service.

Medium
Category
Output Handling
Confidence
90% confidence
Finding

The workflow directs the agent to derive patent-search queries from the user's technical object, mechanism, and key features without a confidentiality check or disclosure that those details will be sent to an external service. If the user supplies an unpublished invention or proprietary technical information, following this procedure could disclose sensitive details to that service; the supplied file does not establish its retention or confidentiality protections. The city-profile context reduces typical exposure because city names and published patent information are generally public, but this reference explicitly extends to users' technical inventions.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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/tools.md (reported line 668)May include surrounding context.

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

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

bash
export PATENTMAX_API_KEY="pm_live_你的密钥"

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 124)May include surrounding context.

健康检查

bash
curl -s "https://api.ip930.com/api/v1/health"

不需要密钥,用来确认网络通不通。

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 · scripts/patentmax_client.py (reported line 102)May include surrounding context.

python
# 设了 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 · scripts/patentmax_client.py (reported line 296)May include surrounding context.

python
if _billing["balance_cents"] < 500 and not KEY_FROM_TRIAL:  # 试用用户不提醒,用完时服务端会给注册指引
            out["_balance_warning"] = (
                "余额不足 ¥5,继续批量检索会很快耗尽。"
                "请先提醒用户到 https://api.ip930.com/features/api-platform 充值。"
            )
    if _billing["free_quota"]:
        left = max(0, _billing["free_quota"] - (_billing["free_used"] or 0))

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 · scripts/patentmax_client.py (reported line 357)May include surrounding context.

python
hint = {
            400: "参数有问题,检查必填项和取值范围。",
            401: "密钥无效或已撤销。确认 PATENTMAX_API_KEY 是 pm_live_ 或 pm_test_ 开头的完整密钥。",
            402: "余额不足。到 https://api.ip930.com/features/api-platform 充值。",
            403: "该密钥没有此接口的权限。",
            404: "没找到这篇专利。确认公开号正确且带国别代码,如 CN109761224A。",
            409: "同一个请求上一次还在处理中。等几秒重跑同一条命令即可,不会重复扣费。",

Tainted flow: 'path' from os.environ.get (line 154, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
90% confidence
Finding

The configurable cache location is not inherently unsafe, but this write persists an API credential using ordinary file-creation permissions and restricts permissions only afterward. On a multi-user system with a permissive umask and traversable cache directory, another local user could read the key before chmod; if chmod fails, the exception is ignored and the readable credential file can remain.

Content

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

python
path = _trial_key_path()
    try:
        os.makedirs(os.path.dirname(path), exist_ok=True)
        with open(path, "w", encoding="utf-8") as fh:
            json.dump({
                "api_key": key,
                "expires_at": data.get("expires_at"),

The retry guidance promises no duplicate charges despite the documented lack of server-side replay for whole-patent requests.

Medium
Category
Excessive Agency
Confidence
96% confidence
Finding

The retry hint broadly promises that repeating a request will not charge again, while the patent-cache documentation states that the whole-patent endpoint does not retain responses for server-side replay. If a paid request completes upstream but its response is lost, no local cache is saved and the instructed retry can incur another charge.

Content

No source excerpt is available for this finding.

Tainted flow: '_ledger_path()' from os.environ.get (line 461, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

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

python
def _save_ledger(ledger):
    try:
        with open(_ledger_path(), "w", encoding="utf-8") as fh:
            json.dump(ledger, fh, ensure_ascii=False)
    except OSError:
        pass

Static analysis

No suspicious patterns detected.