Back to skill

Security audit

外观专利以图搜图

Security checks for vulnerabilities and agentic risk

Overview

This patent-search skill needs review because automatic downloads can expose your API key and save images outside the intended folder.

Prefer a corrected version that restricts authenticated downloads to the trusted HTTPS service and confines image filenames to the output folder. Photos are sent to PatentMax, so consider confidentiality before using it. API keys and task records persist locally, and service-side searches can continue after the command exits.

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 (14)

Tainted flow: 'req' from os.environ.get (line 154, 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_image_search.py (reported line 158)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_error(exc.read().decode("utf-8", "replace"))

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

Critical
Category
Data Flow
Confidence
98% confidence
Finding

Sending the API key to the intended PatentMax service is legitimate, but _open also accepts absolute URLs and unconditionally attaches the Authorization header. Server-provided figure_path values reach this function through try_download, so a malicious or compromised response can direct the client's bearer token to an attacker-controlled host; HTTP URLs are also accepted.

Content

Scanner excerpt · scripts/patentmax_image_search.py (reported line 241)May include surrounding context.

python
req.add_header("Content-Type", "application/json")
    for key, value in (headers or {}).items():
        req.add_header(key, value)
    return urllib.request.urlopen(req, timeout=TIMEOUT)


def request(path, method="GET", body=None, headers=None, raw=False):

Code capability 'env' detected in scripts/patentmax_image_search.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_image_search.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.

The photo-identification workflow lacks a warning that the user's product image is sent to a third-party service.

Medium
Category
Output Handling
Confidence
93% confidence
Finding

The workflow directs the agent to submit the user's product image for identification before disclosing third-party image processing or obtaining informed consent; the later confirmation concerns the paid search, not the initial upload. Product photos can expose confidential, unreleased designs, making this omission particularly relevant to a pre-launch patent-search skill. PatentMax branding makes the service association apparent but does not clearly explain image transmission or handling, and the script's actual behavior cannot be verified from this file alone.

Content

No source excerpt is available for this finding.

The skill instructs the agent to relay Chinese error messages verbatim without offering a language choice.

Medium
Category
Output Handling
Confidence
97% confidence
Finding

The die() docstring explicitly describes messages as user-facing Chinese explanations and directs the AI to repeat them unchanged, prohibiting rephrasing. This imposes Chinese for error responses without user opt-in or a documented locale-specific justification; the same instruction also appears at L014.

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

python
# 密钥版(TRIAL_SOURCE 为空):必须设 PATENTMAX_API_KEY,不领试用。
TRIAL_SOURCE = "design-image-search"
TRIAL_GROUP = "image-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_image_search.py (reported line 195)May include surrounding context.

python
if API_KEY:
        return API_KEY
    if not TRIAL_SOURCE:
        die("还没有设置 PatentMax 密钥。到 https://api.ip930.com/features/api-platform 注册(新用户送 ¥50 体验额度)"
            "并创建密钥,设成环境变量 PATENTMAX_API_KEY=pm_live_xxx 后,再运行同一条命令。", EXIT_INPUT)
    API_KEY = _load_trial_key() or _claim_trial_key()
    KEY_FROM_TRIAL = True

Tainted flow: 'path' from os.environ.get (line 171, 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_image_search.py (reported line 174)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"),

Tainted flow: 'operation' from os.environ.get (line 631, 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_image_search.py (reported line 360)May include surrounding context.

python
record.update({k: v for k, v in fields.items() if v is not None})
    try:
        os.makedirs(os.path.dirname(_task_path(operation)), exist_ok=True)
        with open(_task_path(operation), "w", encoding="utf-8") as fh:
            json.dump(record, fh, ensure_ascii=False, indent=2)
    except OSError:
        pass

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

python
"qualified_degraded": "检索完成,但为了找到结果放宽过条件,排在后面的相似度一般,要保守看。",
    "review_required": "结果需要人工复核。",
}
DEMO_IMAGE_URL = "https://api.ip930.com/demo/image-search-demo.png"
DEMO_BRAND = "安克"
MAX_IMAGE_BYTES = 10 * 1024 * 1024

The documented 30-second command limit is not enforced; network requests and result delivery can block substantially longer.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The polling deadline does not bound the duration of individual network calls, which use a 60-second timeout, and successful delivery performs numerous sequential downloads outside that deadline. A slow or malicious endpoint can therefore occupy the foreground agent far beyond the promised 30 seconds, potentially causing host termination or denying interactive availability.

Content

No source excerpt is available for this finding.

Tainted flow: 'path' from os.environ.get (line 605, 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_image_search.py (reported line 606)May include surrounding context.

python
docx = try_download(f"/api/v1/reports/{urllib.parse.quote(report_id)}/files/report.docx")
    if docx:
        path = os.path.abspath(os.path.join(target, f"{REPORT_NAME}_{stem}.docx"))
        with open(path, "wb") as handle:
            handle.write(docx)
        files[REPORT_NAME] = path
    else:

Tainted flow: 'full' from os.environ.get (line 611, 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_image_search.py (reported line 612)May include surrounding context.

python
else:
        out["docx_note"] = "这次没有生成 Word 报告,结论以下面的摘要和完整结果为准。"
    full = os.path.abspath(os.path.join(target, f"{REPORT_NAME}_{stem}_结果.json"))
    with open(full, "w", encoding="utf-8") as handle:
        json.dump(payload, handle, ensure_ascii=False, indent=2)
    files["完整结果"] = full
    out["files"] = files

Static analysis

No suspicious patterns detected.