Back to skill

Security audit

MinerU OCR Local & API

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its MinerU OCR purpose, but API mode handles credentials, document uploads, remote URLs, and output paths too broadly for sensitive documents.

Install only if you trust the MinerU API endpoint and are comfortable with selected documents being uploaded in API mode. Prefer --mode local for sensitive files, avoid custom MINERU_API_BASE_URL values unless you fully control the endpoint, use session-only tokens where possible, and set an explicit download directory for outputs.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lib.py:129
Finding

Bearer Token Disclosure Through an Unrestricted API Base URL

Content
View full analysis
httpx.Client: return httpx.Client( timeout=config.timeout, headers={ "Authorization": f"Bearer {config.token}", "Accept": "application/json", "User-Agent": "mineru-ocr-local-api-skill/1.1.0", }, ) ``` ### Technical Analysis `MINERU_API_BASE_URL` accepts an arbitrary scheme and host. HTTPS is added only when the supplied value has no scheme; an explicitly supplied `http://` URL remains permitted. The HTTP client attaches `MINERU_API_TOKEN` as a bearer token to every API request made through that client. Consequently, an attacker who can influence the environment or runtime configuration can redirect authenticated API requests to an attacker-controlled server. If HTTP is selected, the token can also be exposed in plaintext to parties capable of observing or modifying network traffic. Custom API endpoints are a documented feature, but the implementation does not enforce transport security, verify that the destination is trusted, or warn that the production credential will be sent to the configured host. ### Attack Path 1. An attacker influences `MINERU_API_BASE_URL`, such as through a poisoned environment, deployment configuration, or wrapper script. 2. The value is set to `https://attacker.example` or `http://attacker.example`. 3. A user or agent runs the skill in API mode with `MINERU_API_TOKEN` configured. 4. `_make_client()` installs the token in the default `Authorization` header. 5. The skill submits a request to the attacker-control ...[truncated 736 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lib.py:658
Finding

Server-Controlled Upload and Download URLs Permit SSRF and Document Disclosure

Content
View full analysis
= 400: raise RuntimeError( f"Failed to download MinerU archive ({response.status_code}): {response.text[:200]}" ) with zip_path.open("wb") as handle: for chunk in response.iter_bytes(): handle.write(chunk) ``` ```python def _upload_file(*, upload_url: str, path: Path) -> None: with path.open("rb") as handle: try: response = httpx.put( upload_url, content=handle.read(), timeout=DEFAULT_TIMEOUT, follow_redirects=True, ) except httpx.TimeoutException as exc: raise RuntimeError(f"Timed out while uploading {path.name} to MinerU") from exc except httpx.RequestError as exc: raise RuntimeError(f"Failed to upload {path.name} to MinerU: {exc}") from exc if response.status_code not in (200, 201, 204): raise RuntimeError( f"MinerU upload failed ({response.status_code}): {response.text[:200]}" ) ``` ### Technical Analysis The skill trusts `upload_url` and `full_zip_url` values returned in API responses and performs requests to them without validating: - The URL scheme - The destination hostname or port - Whether the resolved address is loopback, link-local, private, or r ...[truncated 2536 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lib.py:744
Finding

Remote Task Identifiers Permit Artifact Path Traversal

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (11)

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · scripts/lib.py (reported line 108)May include surrounding context.

python
raw}")
    return value


def _missing_api_token_message() -> str:
    if os.name == "nt":
        current_session = '$env:MINERU_API_TOKEN="YOUR_MINERU_TOKEN"'
        persist = 'setx MINERU_API_TOKEN "YOUR_MINERU_TOKEN"'
        reopen = "After setx, restart Codex/Cursor or open a new terminal."
    else:
        current_session = 'export MINERU_API_TOKEN="YOUR_MINERU_TOKEN"'
        persist = 'echo \'export MINERU_API_TOKEN="YOUR_MINERU_TOKEN"\' >> ~/.bashrc'
        reopen = "Open a new shell after updating your profile."

    return "\n".join(
        [
            "MINERU_API_TOKEN not configured for API mode.",
            "Set it in your environment before using --mode api.",
            f"Docs: {DOCS_URL}",
            f"One-shot command: {current_session}",
            f"Persist for future sessions: {persist}",
            reopen,
            "If you want local parsing instead, use --mode local with a configured MinerU runtime.",
        ]
    )


def get_config() -> Config:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill clearly instructs use of shell execution, environment variables, file reads/writes, and network access, but it does not declare an explicit tool scope such as permissions or allowed-tools. That increases the chance an agent will invoke powerful capabilities without clear policy boundaries, making misuse, overreach, or accidental data exposure more likely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill promotes hosted API mode for local files but does not prominently warn that using --mode api with --file-path uploads the user's local document to an external MinerU service. In a document-processing skill, this is especially sensitive because PDFs and images often contain confidential business, legal, financial, or personal information.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The constant sets the default local parsing language to "ch", and later local configuration falls back to that value when the user does not explicitly choose a language. This imposes a specific locale by default without offering opt-in at the policy level or documenting a region-specific justification in the file.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/lib.py (reported line 497)May include surrounding context.

python
if config.device_mode:
        command.extend(["-d", config.device_mode])

    completed = subprocess.run(
        command,
        capture_output=True,
        text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/lib.py (reported line 794)May include surrounding context.

python
if not curl_bin:
        raise RuntimeError("curl is not available for MinerU archive download fallback.")

    result = subprocess.run(
        [
            curl_bin,
            "-L",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

In API mode, the function uploads the full local document to a remote MinerU service without any explicit in-code consent gate, warning, or privacy disclosure at the point of transfer. Because this skill handles potentially sensitive PDFs and images, silent exfiltration to a third-party service can violate user expectations, policy, or data-handling requirements.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The configuration section suggests using setx to persist the API token but does not warn that this stores credentials on the system for future sessions and may broaden exposure to other processes or users with access to the account. While not a direct secret leak by itself, it normalizes insecure credential handling and can lead to accidental retention of sensitive tokens.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The code automatically extracts the downloaded ZIP archive into a task directory, creating files and directories on the local filesystem. Although this behavior is part of result handling, this file provides no user-facing disclosure that API parsing will write and unpack artifacts locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code writes the JSON result to a filesystem path by default whenever --stdout is not used, including creating parent directories and saving the file. Although the CLI help documents the output options, there is no explicit user-facing warning at execution time that parsed document data will be persisted to a temp or user-specified location.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: httpx has 2 known advisory(ies) (CVE-2021-41945 (Improper Input Validation in httpx); CVE-2021-41945 (Encode OSS httpx <=1.0.0.beta0 is affected by improper input validation in `http)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The dependency specifier httpx>=0.27,<1 does not pin to a specific patched version, so builds may resolve to different releases over time and the manifest does not demonstrate that vulnerable versions are excluded. In a skill that performs API communication and local-file upload, relying on an unverifiable HTTP client version weakens supply-chain assurance and could expose the runtime to known library flaws if an affected release is installed.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.