Back to skill

Security audit

技术路线分析 · PatentMax

Security checks for vulnerabilities and agentic risk

Overview

This skill looks like a real PatentMax integration, but it should be reviewed because it sends confidential patent and business planning data plus an API key to a configurable external endpoint without strong scoping or privacy warnings.

Install only if you are comfortable sending patent-roadmap materials and business constraints to PatentMax. Use sanitized summaries when possible, protect PATENTMAX_API_KEY like a secret, avoid setting PATENTMAX_BASE_URL, confirm charges before using --yes, and treat outputs as business and technical guidance rather than legal advice.

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/patentmax_roadmap.py:38
Finding

Unrestricted API Base URL Can Expose Credentials and Confidential Patent Data

Content
View full analysis

Vulnerability Details

File Location: scripts/patentmax_roadmap.py, lines 38 and 76–80
Vulnerability Type: Unrestricted service endpoint override resulting in credential and sensitive-data disclosure
Risk Level: High

Complete Code Snippet

python
BASE_URL = os.environ.get("PATENTMAX_BASE_URL", "https://api.ip930.com").rstrip("/")
API_KEY = os.environ.get("PATENTMAX_API_KEY", "").strip()
python
url = path if path.startswith("http") else f"{BASE_URL}{path}"
data = json.dumps(body, ensure_ascii=False).encode("utf-8") if body is not None else None
req = urllib.request.Request(url, data=data, method=method)
req.add_header("Authorization", f"Bearer {API_KEY}")
req.add_header("Accept", "application/json")

Technical Analysis

The client accepts PATENTMAX_BASE_URL directly from the process environment without validating its scheme, hostname, port, or destination. The shared request() function then attaches the PatentMax bearer token to every request sent through that endpoint.

Consequently, a party capable of influencing the process environment can redirect requests to an attacker-controlled server. The code does not require HTTPS and does not restrict the destination to api.ip930.com. For report-creation requests, the request body may also contain unpublished technical materials, experimental evidence, future business plans, patent assets, budgets, competitors, disclosure dates, and confidentiality boundaries.

This issue does not independently grant an external attacker control of the environment. Exploitation requires control over, or influence on, the environment used to launch the Skill—for example, a compromised wrapper, CI configuration, shell profile, container configuration, or agent runtime.

Attack Path

  1. An attacker gains the ability to modify the environment from which the Skill is launched.
  2. The attacker sets PATENTMAX_BASE_URL to an attacker-controlled endpoint, such as https://attacker.example.

...[truncated 1259 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the production PATENTMAX_BASE_URL override if runtime endpoint customization is unnecessary.
  2. If an override is required for testing, parse and strictly validate it with urllib.parse.urlsplit.
  3. Require the https scheme and reject plaintext HTTP.
  4. Allowlist exact approved hostnames, such as api.ip930.com; do not rely on substring or suffix matching.
  5. Reject embedded credentials, fragments, unexpected ports, malformed URLs, and non-empty paths where a host-only base URL is expected.
  6. Use separate, minimally privileged test credentials for development endpoints. Never send production credentials to configurable test hosts.
  7. Require an explicit development-only flag before permitting a non-production endpoint, and fail closed by default.
  8. Before adding the Authorization header, verify that the final request destination remains an approved origin.
  9. Review redirect behavior and prevent authorization headers from reaching untrusted redirect targets.
  10. Rotate any API key that may have been used while the endpoint environment was untrusted, and review service logs for unauthorized report creation or data access.

A hardened validation pattern should enforce the approved origin before any authenticated request is created:

python
from urllib.parse import urlsplit

APPROVED_HOSTS = {"api.ip930.com"}

def validate_base_url(value):
    parsed = urlsplit(value)
    if parsed.scheme != "https":
        raise ValueError("The API endpoint must use HTTPS.")
    if parsed.hostname not in APPROVED_HOSTS:
        raise ValueError("The API endpoint host is not approved.")
    if parsed.username or parsed.password or parsed.fragment:
        raise ValueError("Credentials and fragments are not permitted.")
    if parsed.port not in (None, 443):
        raise ValueError("Unexpected API endpoint port.")
    return f"https://{parsed.hostname}"
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (18)

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

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The tool sends sensitive user-provided patent materials and business roadmap context to a remote service, and the destination base URL is overridable via PATENTMAX_BASE_URL from the environment. In an agent setting, this enables exfiltration of confidential R&D and strategy data to an unintended host if the environment is manipulated or misconfigured.

Content

Scanner excerpt · scripts/patentmax_roadmap.py (reported line 87)May include surrounding context.

python
req.add_header(key, value)

    try:
        with urllib.request.urlopen(req, timeout=TIMEOUT) as response:
            payload = response.read()
            return payload if raw else json.loads(payload.decode("utf-8"))
    except urllib.error.HTTPError as exc:

Lp1

High
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The script performs outbound network requests to an external API, creates paid jobs, polls long-running operations, and downloads report files, but the declared permissions apparently do not disclose network capability. Undeclared network access is a real security concern for agent skills because it enables data egress and external side effects outside expected policy boundaries.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The script performs outbound network requests to an external API, creates paid jobs, polls long-running operations, and downloads report files, but the declared permissions apparently do not disclose network capability. Undeclared network access is a real security concern for agent skills because it enables data egress and external side effects outside expected policy boundaries.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill explicitly encourages users to provide internal business constraints and confidential planning inputs, and elsewhere says such internal information should still be supplied to generate useful advice. Without a clear privacy, retention, and confidentiality warning, users may disclose sensitive strategic, technical, or trade-secret-adjacent information to an external service without understanding exposure risks.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description uses broad trigger phrasing such as asking which direction to pursue, how to allocate patent budget, or how to design around competitors' patents, without tightly constraining when the skill should be invoked. That can cause over-invocation on ambiguous user requests and route users into a paid external workflow that solicits sensitive business and IP strategy details, increasing the risk of unnecessary data disclosure and inappropriate operational guidance.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill content and examples are predominantly in Chinese and do not clearly offer language choice, which can cause users to misunderstand the scope, cost, disclosure requirements, and legal caveats. In a skill handling patent strategy and confidential business constraints, language mismatch raises the chance of malformed inputs, uninformed consent, and accidental disclosure of sensitive information.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file contains user-facing instructional content exclusively in Chinese, and there is no indication that the skill is region-specific or that users may choose another language. That can violate language/locale policy expectations when a skill forces a specific language without user opt-in.

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 · references/faq.md (reported line 126)May include surrounding context.

实在没有就直接发 HTTP 请求:

bash
curl -s -X POST "https://api.ip930.com/api/v1/reports" \
  -H "Authorization: Bearer $PATENTMAX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 自定义唯一串" \

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file contains operational instructions solely in Chinese, and nowhere indicates that the user may choose another language or that the skill is intentionally limited 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.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code explicitly states that errors will be returned with Chinese prompts, and the CLI help/docstrings throughout the file are written only in Chinese. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly justified, which is not documented here.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

This tool is explicitly designed to transmit sensitive inputs such as technical方案, competitors, budget, disclosure timing, and confidentiality limits to an external API. In the context of a patent-roadmap skill, that data is especially sensitive, so external transmission materially increases confidentiality and trade-secret exposure risk.

Content

Scanner excerpt · scripts/patentmax_roadmap.py (reported line 74)May include surrounding context.

python
def request(path, method="GET", body=None, headers=None, raw=False):
    if not API_KEY:
        die("未设置 API 密钥。请先 export PATENTMAX_API_KEY=pm_live_xxx,"
            "密钥在 https://api.ip930.com/features/api-platform 创建。")

    url = path if path.startswith("http") else f"{BASE_URL}{path}"
    data = json.dumps(body, ensure_ascii=False).encode("utf-8") if body is not None else None

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 · README.md (reported line 70)May include surrounding context.

md
400: "参数不正确。subject 至少 3 字,materials 至少 5 字,objective 至少 3 字;"
                 "roadmap_context 每项最长 2000 字(公开时点/申请偏好/预算/保密边界为 500 字)。",
            401: "密钥无效或已撤销。",
            402: "余额不足,到 https://api.ip930.com/features/api-platform 充值。",
            403: "该密钥没有此接口的权限。",
            404: "任务或报告不存在。确认 id 抄全了。",
            409: "任务冲突:报告还没跑完就来取结果,或同一个 Idempotency-Key 正在处理中。",

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/faq.md (reported line 17)May include surrounding context.

md
400: "参数不正确。subject 至少 3 字,materials 至少 5 字,objective 至少 3 字;"
                 "roadmap_context 每项最长 2000 字(公开时点/申请偏好/预算/保密边界为 500 字)。",
            401: "密钥无效或已撤销。",
            402: "余额不足,到 https://api.ip930.com/features/api-platform 充值。",
            403: "该密钥没有此接口的权限。",
            404: "任务或报告不存在。确认 id 抄全了。",
            409: "任务冲突:报告还没跑完就来取结果,或同一个 Idempotency-Key 正在处理中。",

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/faq.md (reported line 126)May include surrounding context.

md
400: "参数不正确。subject 至少 3 字,materials 至少 5 字,objective 至少 3 字;"
                 "roadmap_context 每项最长 2000 字(公开时点/申请偏好/预算/保密边界为 500 字)。",
            401: "密钥无效或已撤销。",
            402: "余额不足,到 https://api.ip930.com/features/api-platform 充值。",
            403: "该密钥没有此接口的权限。",
            404: "任务或报告不存在。确认 id 抄全了。",
            409: "任务冲突:报告还没跑完就来取结果,或同一个 Idempotency-Key 正在处理中。",

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_roadmap.py (reported line 96)May include surrounding context.

python
400: "参数不正确。subject 至少 3 字,materials 至少 5 字,objective 至少 3 字;"
                 "roadmap_context 每项最长 2000 字(公开时点/申请偏好/预算/保密边界为 500 字)。",
            401: "密钥无效或已撤销。",
            402: "余额不足,到 https://api.ip930.com/features/api-platform 充值。",
            403: "该密钥没有此接口的权限。",
            404: "任务或报告不存在。确认 id 抄全了。",
            409: "任务冲突:报告还没跑完就来取结果,或同一个 Idempotency-Key 正在处理中。",

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file tells the user to create an API key and export it as PATENTMAX_API_KEY, which is credential handling. The description provides no warning about protecting the key, avoiding shell history leakage, or not committing secrets into files/scripts, so the skill omits a basic user-facing warning about sensitive data handling.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

This markdown file instructs users to print a prefix of PATENTMAX_API_KEY and set live credentials in shell commands, but it does not warn users about secret exposure risks such as shell history, shared terminals, or screen sharing. Because SQP-2 applies to markdown files when descriptions omit warnings affecting privacy or system integrity, the missing caution around credential handling is a valid documentation safety gap.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/patentmax_roadmap.py (reported line 153)May include surrounding context.

python
context.update({k: str(v).strip() for k, v in loaded.items() if str(v).strip()})

    for key in CONTEXT_FIELDS:
        value = getattr(args, key, None)
        if value and value.strip():
            context[key] = value.strip()
    return context

Static analysis

No suspicious patterns detected.