Back to skill

Security audit

Baidu image recognize

Security checks for vulnerabilities and agentic risk

Overview

This image-recognition skill mostly matches its purpose, but it can fetch arbitrary URLs and forward the downloaded content to Baidu without URL, size, or content safeguards.

Review before installing. Use this only for images you are comfortable sending to Baidu, avoid private or sensitive images, and avoid remote URLs unless the runtime blocks private/internal addresses and enforces image size and type limits. The API key use is expected, but the current URL handling could expose internal network responses in permissive environments.

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/image_recognize.py:96
Finding

Server-Side Request Forgery and Unbounded Remote Image Download

Content
View full analysis

Vulnerability Details

File Location: scripts/image_recognize.py:96-101
Vulnerability Type: Server-Side Request Forgery (SSRF), unintended third-party data disclosure, and unbounded response buffering
Risk Level: Medium

Vulnerable Code

python
# 处理网络 URL
if value.startswith(("http://", "https://")):
    try:
        response = requests.get(value, timeout=30)
        response.raise_for_status()
        return base64.b64encode(response.content).decode()
    except requests.RequestException as e:
        raise Exception(f"下载网络图片失败: {e}")

The downloaded content is later transmitted to the external recognition service:

python
payload = {
    "image_b64": image_b64
}

try:
    response = requests.post(api_url, json=payload, headers=headers, timeout=30)

Technical Analysis

The Skill intentionally supports remote image URLs, but it fetches a user-controlled HTTP or HTTPS destination without validating the destination host or resolved IP address. It does not reject loopback, link-local, private, reserved, multicast, or cloud metadata addresses.

The requests library follows redirects by default. Consequently, checking only the original string for an http:// or https:// prefix does not prevent an initially public URL from redirecting to an internal service. DNS rebinding and resolution changes may also bypass simplistic hostname-based controls unless the resolved address used for the connection is validated.

The response is loaded in full through response.content before encoding. No response-size limit, content-type validation, or image decoding check is enforced. This contradicts the documented 4 MB image constraint and allows excessive memory consumption.

After retrieval, the response bytes are Base64-encoded and submitted to Baidu's Qianfan endpoint by recognize_image. Encoding does not provide confidentiality or sanitization. If the URL resolves to a sensitive internal resource, its response content may therefore ...[truncated 2120 chars]

Remediation
View remediation

Remediation Suggestions

  1. Permit remote fetching only when required. For higher-assurance deployments, require callers to upload local image bytes rather than allowing arbitrary URLs.
  2. Resolve the destination before connecting and reject all loopback, private, link-local, multicast, unspecified, reserved, and cloud metadata addresses for both IPv4 and IPv6.
  3. Disable automatic redirects with allow_redirects=False, or validate the scheme, hostname, resolved address, and port at every redirect hop.
  4. Defend against DNS rebinding by ensuring the validated address is the address actually used for the connection. Avoid relying solely on hostname string checks.
  5. Use streaming downloads and enforce a strict byte limit, such as the documented 4 MB maximum. Abort immediately when Content-Length exceeds the limit or when streamed bytes cross it.
  6. Allow only expected image media types, reject ambiguous or missing content types as appropriate, and verify the downloaded bytes with a trusted image decoder before forwarding them.
  7. Restrict destination ports to those required for image retrieval, normally TCP 80 and 443.
  8. Apply network-level egress controls that prevent the Skill process from reaching internal networks, metadata services, and administrative endpoints.
  9. Obtain explicit user consent before sending image content to the third-party recognition provider, particularly where images may contain personal or confidential information.
  10. Add tests covering direct private addresses, IPv6 loopback, numeric-IP representations, public-to-private redirects, DNS rebinding scenarios, non-image responses, oversized bodies, and chunked responses without Content-Length.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (10)

Tainted flow: 'headers' from os.environ.get (line 300, credential/environment) → requests.post (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/image_recognize.py (reported line 130)May include surrounding context.

python
}

    try:
        response = requests.post(api_url, json=payload, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The documented purpose is generic image recognition, but the behavior also includes fetching remote images and exposing similar-image or external reference/search results. That expands the trust boundary beyond simple classification into third-party content retrieval and outbound network access, which can cause privacy leakage, SSRF-style fetching risks, or unexpected data disclosure to external services.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill requires environment-variable access and makes network-capable requests, but it does not declare an explicit tool scope or permissions boundary. This weakens reviewability and least-privilege enforcement, making it easier for a caller or runtime to invoke capabilities the user did not clearly authorize, especially when handling API keys and remote image URLs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill does not clearly warn users that submitted images and network image URLs may be transmitted to Baidu for processing. This creates a meaningful privacy and compliance risk because users may unknowingly send personal, confidential, or regulated data to a third-party provider.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The trigger condition is broad enough to activate on many generic image-related requests without clearly requiring informed user intent for external processing. In context, that increases the chance the skill is invoked on sensitive images or URLs and sends data to Baidu or other remote endpoints when the user only asked for general help.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill advertises image recognition, but the code also retrieves and returns similar-image results from web search data (rag_data.search_results). This expands functionality beyond the stated scope and may surprise users by pulling in third-party web content and URLs, increasing privacy and trust risks.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The _normalize_image docstring says '裸 base64 → 原样返回', implying plain base64 input is supported. In actual code, after handling data URIs and HTTP(S) URLs, any value that is not an existing local path causes FileNotFoundError, so raw base64 strings are not accepted as documented.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code downloads user-supplied remote images and then uploads the image bytes to an external Baidu API, but the user-facing flow shown here does not present an explicit warning or consent step about external network transmission. In a skill handling potentially sensitive local files or private image URLs, this can lead to unintended disclosure of image contents and metadata to third parties.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The skill transmits user-provided image content to an external recognition service. In this skill context, external transmission is functionally necessary, but it is still a real privacy/security concern because images may contain sensitive personal, medical, or confidential information, and the code does not show minimization, redaction, or explicit consent controls.

Content

Scanner excerpt · scripts/image_recognize.py (reported line 130)May include surrounding context.

python
}

    try:
        response = requests.post(api_url, json=payload, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file's natural-language descriptions and printed output are written in Chinese throughout, but there is no indication that the skill is intentionally limited to Chinese-speaking users or that language selection is supported. Under the policy, forcing a specific language without opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.