Back to skill

Security audit

Vision Recognition Ocr

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate Baidu vision and OCR skill, but it can upload any readable user-specified local file to Baidu without image validation or clear consent controls.

Review before installing. Use only with images or documents you are comfortable sending to Baidu, prefer dedicated least-privilege Baidu credentials, and avoid passing untrusted or agent-suggested local paths until the skill adds file-type, path-scope, size, and confirmation safeguards.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/_baidu_image_classify.py:46
Finding

Arbitrary Readable Local Files Can Be Uploaded to Baidu APIs

Content
View full analysis
str: p = Path(image_path) if not p.exists() or not p.is_file(): raise FileNotFoundError(f"image_path not found: {image_path}") return base64.b64encode(p.read_bytes()).decode("utf-8") def build_image_payload(payload: Dict[str, Any]) -> Dict[str, Any]: data: Dict[str, Any] = {} image_base64 = payload.get("image_base64") image_path = payload.get("image_path") image_url = payload.get("url") if image_base64: if image_base64.startswith("data:") and "," in image_base64: image_base64 = image_base64.split(",", 1)[1] data["image"] = image_base64 elif image_path: data["image"] = read_image_base64(image_path) elif image_url: data["url"] = image_url else: raise ValueError("One of image_base64/image_path/url must be provided") return data ``` This shared function is used by every OCR and image-classification entry point. ### Technical Analysis The Skill declares that `image_path` identifies a local image, but the implementation only checks that the supplied path exists and is a regular file. It does not verify: - That the file contains a supported image format. - That its detected MIME type matches an allowed image type. - That the path is inside an approved workspace or upload directory. - That the path does not resolve through a symbolic link. - That the file is within a safe size limit. - That the user has explicitly approved transmitting the selected local file. `Path.read_bytes()` therefore reads any regular file accessible to the Skill process. Base64 encoding provides no confidentiality; it only serializes the file for submission. The resulting value is placed in the `image` request param ...[truncated 1813 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/_baidu_image_classify.py:31
Finding

OAuth Secrets and Access Tokens Are Included in Request URLs

Content
View full analysis
str: params = { "grant_type": "client_credentials", "client_id": api_key, "client_secret": secret_key, } resp = requests.post(TOKEN_URL, params=params, timeout=20) resp.raise_for_status() data = resp.json() token = data.get("access_token") if not token: raise RuntimeError(f"Failed to get access_token: {data}") return token ``` ```python def call_image_classify(endpoint: str, data: Dict[str, Any]) -> Dict[str, Any]: api_url = f"{BASE_API_URL}/{endpoint}" headers = {"Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json"} bearer = pick_bearer_token() if bearer.startswith("bce-v3/"): headers["Authorization"] = f"Bearer {bearer}" resp = requests.post(api_url, headers=headers, data=data, timeout=30) else: api_key, secret_key = pick_oauth_credentials() token = get_access_token(api_key, secret_key) resp = requests.post(f"{api_url}?access_token={token}", headers=headers, data=data, timeout=30) ``` From `scripts/_baidu_ocr.py`: ```python def get_access_token(api_key: str, secret_key: str) -> str: params = { "grant_type": "client_credentials", "client_id": api_key, "client_secret": secret_key, } resp = requests.post(TOKEN_URL, params=params, timeout=20) resp.raise_for_status() data = resp.json() token = data.get("access_token") if not token: raise RuntimeError(f"Failed to get access_token: {json.dumps(data, ensure_ascii=False)}") return token ``` ```python def call_ocr(endpoint: str, data: Dict[str, An ...[truncated 2879 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (22)

Tainted flow: 'params' from os.getenv (line 32, 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/_baidu_image_classify.py (reported line 37)May include surrounding context.

python
"client_id": api_key,
        "client_secret": secret_key,
    }
    resp = requests.post(TOKEN_URL, params=params, timeout=20)
    resp.raise_for_status()
    data = resp.json()
    token = data.get("access_token")

Tainted flow: 'token' from os.getenv (line 100, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The access token is embedded in the request URL query string, which can expose it through logs, monitoring systems, proxies, browser/debug tooling, or error messages even when TLS is used. Tokens in URLs are generally more leak-prone than tokens in headers and can enable unauthorized API use if captured.

Content

Scanner excerpt · scripts/_baidu_image_classify.py (reported line 101)May include surrounding context.

python
else:
        api_key, secret_key = pick_oauth_credentials()
        token = get_access_token(api_key, secret_key)
        resp = requests.post(f"{api_url}?access_token={token}", headers=headers, data=data, timeout=30)

    resp.raise_for_status()
    result = resp.json()

Tainted flow: 'params' from os.getenv (line 31, 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/_baidu_ocr.py (reported line 36)May include surrounding context.

python
"client_id": api_key,
        "client_secret": secret_key,
    }
    resp = requests.post(TOKEN_URL, params=params, timeout=20)
    resp.raise_for_status()
    data = resp.json()
    token = data.get("access_token")

Tainted flow: 'token' from os.getenv (line 64, 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/_baidu_ocr.py (reported line 65)May include surrounding context.

python
else:
        api_key, secret_key = pick_oauth_credentials()
        token = get_access_token(api_key, secret_key)
        resp = requests.post(f"{api_url}?access_token={token}", headers=headers, data=data, timeout=30)

    resp.raise_for_status()
    result = resp.json()

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code clearly supports image input via local path, URL, and base64, and it prepares/authenticates requests to Baidu image-classify APIs, which aligns with the image recognition portion of the description. However, the declared purpose prominently includes OCR/text extraction, including invoices and tables, while the supplied code only targets the image-classify base API and contains no OCR endpoints, text-recognition request building, or OCR-specific processing. This is a material description-versus-behavior mismatch for the provided chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The code chunk only supports calling Baidu OCR endpoints and managing authentication tokens. There is no evidence of vehicle, animal, or plant recognition logic, nor any parsing/loading of image inputs from local paths, URLs, or base64. While OCR is consistent with part of the description, the declared description materially overstates the implemented capabilities in this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The supplied code chunk has a much narrower purpose than the declared description. It builds an image payload and calls an image classification function specifically with the category 'animal'. There is no OCR logic, no vehicle or plant recognition, and no invoice/table/text extraction behavior shown here. While the input handling appears consistent with image input support, the primary purpose of this code chunk is limited to animal recognition, making the broad declared description materially inaccurate for this specific code.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The code chunk is narrowly focused on car recognition: it builds an image payload and calls call_image_classify("car", data). While vehicle recognition is part of the declared description, the description claims a much broader multifunction skill including OCR and recognition of animals/plants/invoices/tables. Those capabilities are not present in this code chunk. Input support for image payloads may be inherited from build_image_payload, but the primary implemented behavior here is only car classification, making the declared description materially broader than the actual behavior shown.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description presents a combined image-recognition plus OCR skill covering object/category recognition (vehicle/animal/plant) and multiple OCR use cases. The supplied code chunk, however, is narrowly focused on generic OCR via Baidu's accurate_basic API. While OCR is consistent with part of the declared purpose, the broader recognition claims are not represented in this code. This is a material description/behavior mismatch because the actual primary behavior here is only OCR, not the full multimodal recognition capability described.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description presents the skill as a broader multimodal recognition tool covering both image classification (e.g., vehicle/animal/plant recognition, 看图识别) and OCR extraction from multiple document types. However, the supplied code only performs a generic OCR operation via call_ocr("general_basic", data). It accepts an image payload and optional OCR flags, but contains no logic for image classification, no vehicle/animal/plant recognition, and no specialized invoice/table processing in this chunk. This is a description-to-behavior mismatch because the declared primary scope is materially broader than what the code actually does.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill documentation advertises capabilities that require network access, environment-variable credential use, and local file reading, but it does not declare any tool scope or permissions boundary. That increases the chance the agent invokes broader capabilities than users expect, weakening least-privilege and informed-consent controls around sensitive image and OCR data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill states it uses Baidu vision APIs but does not clearly warn users that provided images and the text extracted from them may be transmitted to an external cloud provider. In an OCR skill, this matters because screenshots, invoices, tables, and photos often contain highly sensitive personal or business data, so users may unknowingly expose confidential material.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The helper sends credentials and potentially sensitive image content to external Baidu endpoints, but there is no visible user-consent, warning, or disclosure mechanism in the implementation. In an OCR/vision skill, inputs may include invoices, screenshots, or other personal/business data, so undisclosed third-party transfer creates privacy and compliance risk.

Content

No source excerpt is available for this finding.

Tainted flow: 'data' from requests.post (line 39, network input) → requests.post (network output)

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/_baidu_image_classify.py (reported line 97)May include surrounding context.

python
bearer = pick_bearer_token()
    if bearer.startswith("bce-v3/"):
        headers["Authorization"] = f"Bearer {bearer}"
        resp = requests.post(api_url, headers=headers, data=data, timeout=30)
    else:
        api_key, secret_key = pick_oauth_credentials()
        token = get_access_token(api_key, secret_key)

Tainted flow: 'data' from requests.post (line 39, network input) → requests.post (network output)

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/_baidu_image_classify.py (reported line 101)May include surrounding context.

python
else:
        api_key, secret_key = pick_oauth_credentials()
        token = get_access_token(api_key, secret_key)
        resp = requests.post(f"{api_url}?access_token={token}", headers=headers, data=data, timeout=30)

    resp.raise_for_status()
    result = resp.json()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This helper transmits images or extracted document data to Baidu's remote OCR service without any in-code indication of user consent, privacy notice, or sensitivity checks. In the context of OCR for screenshots, invoices, and tables, this can expose personal, financial, or confidential business data to a third party unexpectedly.

Content

No source excerpt is available for this finding.

Tainted flow: 'data' from requests.post (line 38, network input) → requests.post (network output)

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/_baidu_ocr.py (reported line 61)May include surrounding context.

python
bearer = pick_bearer_token()
    if bearer.startswith("bce-v3/"):
        headers["Authorization"] = f"Bearer {bearer}"
        resp = requests.post(api_url, headers=headers, data=data, timeout=30)
    else:
        api_key, secret_key = pick_oauth_credentials()
        token = get_access_token(api_key, secret_key)

Tainted flow: 'data' from requests.post (line 38, network input) → requests.post (network output)

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/_baidu_ocr.py (reported line 65)May include surrounding context.

python
else:
        api_key, secret_key = pick_oauth_credentials()
        token = get_access_token(api_key, secret_key)
        resp = requests.post(f"{api_url}?access_token={token}", headers=headers, data=data, timeout=30)

    resp.raise_for_status()
    result = resp.json()

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The credential setup section explains how to supply API keys and bearer tokens, but it omits a plain-language warning that the skill performs external network calls using those credentials to process user-supplied data. This creates an informed-consent and data-governance risk, especially in environments where users may assume local-only OCR or may not realize secrets and document contents are involved in third-party processing.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The manifest describes a recognition/OCR skill for processing images from path, URL, or base64, but does not mention credential discovery from environment variables. While network access to Baidu is expected for this skill, reading multiple environment variables for API and bearer tokens introduces a separate capability beyond the stated user-facing function.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The skill is described as vehicle/animal/plant recognition and OCR on images, but this helper pulls credentials from broad, generic environment variables such as BAIDU_API_KEY and BAIDU_SECRET_KEY in addition to vision-specific names. Reading environment variables for credentials is not described in the manifest and is a capability that is not clearly justified by the narrow end-user purpose alone.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest presents the skill as a general image-recognition and OCR capability across multiple domains, but this script is narrowly scoped to calling image classification with the fixed category "car". That is a semantic mismatch between the broad claimed behavior and this file's actual behavior, even though the broader skill may be implemented elsewhere.

Content

No source excerpt is available for this finding.