Back to skill

Security audit

PaddleOCR-VL

Security checks for vulnerabilities and agentic risk

Overview

This OCR skill has a coherent purpose, but it runs unverified Docker images with excessive access to local files and the host network, and it has a filename injection bug.

Review carefully before installing. Use only with non-sensitive files and only if you trust the container publisher and registry. A safer version should pin image digests, remove host networking, avoid root, mount only a staged input file read-only, and fix filename handling before passing paths into executable Python source.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
server.py:114
Finding

Python Code Injection Through a User-Controlled Image Filename

Content
View full analysis
str: return _INLINE_PREAMBLE + _INLINE_BODY.format(container_img_path=container_img_path) def _run_container(image: str, host_image_path: str, timeout: int = 300) -> dict: """Run OCR inside an ephemeral Docker container.""" apath = Path(host_image_path).resolve() if not apath.exists(): return {"status": "error", "message": f"file not found: {host_image_path}"} host_dir = str(apath.parent) container_img = f"/data/{apath.name}" script = _build_inline_script(container_img) ``` The generated script is subsequently executed using: ```python image, "python3", "-c", script, ``` ### Technical Analysis The `image_path` tool argument controls the filename represented by `apath.name`. That filename is inserted directly into a single-quoted Python string using `str.format()`. No Python-string escaping or safe serialization is applied before the resulting source code is supplied to `python3 -c`. A valid existing filename containing a quote, newline, or other Python syntax can therefore terminate the intended string and inject additional Python statements. Using a subprocess argument array prevents shell injection into the host command, but it does not prevent this separate source-code injection because the attacker-controlled value becomes part of executable Python source. ### Attack Path 1. An attacker creates an existing file ...[truncated 1354 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.py:134
Finding

Excessive Container Privileges and Writable Exposure of Arbitrary Host Directories

Content
View full analysis
dict: """Run OCR inside an ephemeral Docker container.""" apath = Path(host_image_path).resolve() if not apath.exists(): return {"status": "error", "message": f"file not found: {host_image_path}"} host_dir = str(apath.parent) container_img = f"/data/{apath.name}" script = _build_inline_script(container_img) cmd = [ "docker", "run", "--rm", "--gpus", "all", "--network", "host", "--user", "root", "-v", f"{host_dir}:/data", image, "python3", "-c", script, ] try: proc = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) ``` ### Technical Analysis The server accepts an arbitrary existing path and mounts that file's entire parent directory into the container. Because no `:ro` option is specified, Docker creates a read-write bind mount. The container also receives the following unnecessary privileges: - Execution as container root through `--user root`. - Direct host-network namespace access through `--network host`. - Access to all available GPUs through `--gpus all`. - Read-write access to every file in the selected parent directory. OCR requires reading an input image, but it does not inherently require write access to the image's entire parent directory, root execution, or host networking. The configuration therefore violates least privilege and significantly increases the consequences of code injection, a malicious dependency, or a compromised image. The documentation's statement that the container has “no network access beyond `--network host`” is also inaccurate: host networking grants network connectivity rather than disabling it. ### Attack Path 1. An attacker ...[truncated 1438 chars]
Remediation
View remediation
``` 6. Mount a separate constrained temporary filesystem only for locations that must be writable. 7. Expose only the GPU devices required by the task rather than all GPUs where feasible. 8. Verify that the input is a regular file and reject directories, device files, sockets, and paths outside an explicitly approved input root. 9. Update `SKILL.md` so that its network and privacy claims accurately match the hardened implementation. ]]>

T08 · Insecure Dependencies

Warning
Location
server.py:34
Finding

Mutable Unverified Container Images Are Executed with Elevated Access

Content
View full analysis
Remediation
View remediation
" ) ``` 2. Maintain separate reviewed digests for standard and Blackwell images. 3. Verify image signatures and provenance using an appropriate mechanism such as Sigstore Cosign or the registry's supported trust framework. 4. Document the expected publisher, repository ownership, digest, release version, and review date. 5. Introduce a controlled update process that scans and reviews a new image before changing the pinned digest. 6. Fail closed when the local image digest does not match the approved value. 7. Generate and review an image software bill of materials and vulnerability scan. 8. Independently harden container execution with read-only mounts, no network access, a non-root user, dropped capabilities, and `no-new-privileges`; digest pinning does not replace runtime isolation. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (21)

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · SKILL.md (reported line 49)May include surrounding context.

1. Install the MCP Server

Add to ~/.config/Claude/claude_desktop_config.json (Claude Desktop) or ~/.claude/settings.json (Claude Code):

json
{

Privileged Container / Container Escape

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

Using host networking reduces container isolation and allows the OCR container to share the host's network namespace, which can expose local services and facilitate data exfiltration if the image is compromised. In this skill's context, that is especially risky because users may process sensitive local documents while trusting the container to be 'local only.'

Content

Scanner excerpt · SKILL.md (reported line 93)May include surrounding context.

md
## Security & Privacy

- Images are processed inside an ephemeral Docker container (`--rm` flag)
- The container has no network access beyond `--network host` (needed for GPU)
- No data leaves the host machine
- The container is destroyed immediately after each OCR run

Privileged Container / Container Escape

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The recommended docker run command uses --network host alongside --user root, substantially reducing container isolation. For an OCR skill, that privilege level is not justified by function, and if the pulled image is malicious or compromised it could directly probe or abuse host-reachable network services while handling local content.

Content

Scanner excerpt · server.py (reported line 353)May include surrounding context.

python
### 第 2 步: 验证容器可以启动

```bash
docker run --rm --gpus all --network host --user root {image} \\
    python3 -c "from paddlex import create_pipeline; print('OK')"
```

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill documents executable capabilities through an MCP server, Docker, and local shell dependencies, but does not declare an explicit tool scope such as permissions or allowed-tools. That omission weakens reviewability and least-privilege enforcement, making it easier for the skill to obtain broader execution than users or platforms may expect.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

The Docker image is referenced with a mutable latest-style tag rather than an immutable digest. Anyone pulling the image later may receive different code than what was originally reviewed, enabling supply-chain compromise with host-accessing OCR workloads.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

This second Docker pull instruction also uses a mutable tag, so the deployed container contents can drift over time or be replaced upstream. Because the skill runs GPU-enabled containers against local files, an unexpected image change could expose sensitive host data or execute unreviewed code.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The security section claims the container has no network access while simultaneously describing host networking, which gives the container the host's network namespace and broad network reach. Misrepresenting this materially increases operational risk because users may trust the skill with sensitive documents under false assumptions about isolation.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

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 · server.py (reported line 55)May include surrounding context.

python
def _detect_gpu_arch() -> dict:
    """Return {arch, image, compute_cap} by querying nvidia-smi."""
    try:
        out = subprocess.check_output(
            ["nvidia-smi", "--query-gpu=name,compute_cap", "--format=csv,noheader"],
            text=True, timeout=10,
        ).strip()

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 · server.py (reported line 89)May include surrounding context.

python
def _docker_image_present(image: str) -> bool:
    """Check whether the Docker image exists locally."""
    try:
        subprocess.check_output(
            ["docker", "image", "inspect", image],
            text=True, stderr=subprocess.DEVNULL, timeout=10,
        )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code mounts the parent directory of a user-supplied path into /data inside a root container. That exposes more host files than necessary to untrusted container code, and the risk is amplified by the skill context because end users may point the tool at sensitive document locations expecting only OCR, not broad directory exposure.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The OCR skill runs a remote Docker image with both host networking and root privileges even though document parsing does not inherently require either. In context, this is more dangerous because the tool is designed to process user-specified files, so a compromised image or dependency chain would gain broad access to host networking and mounted data during routine use.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

This subprocess call launches a Docker container using a command that includes dangerous runtime flags (--network host, --user root) and mounts a host directory derived from user input. While not shell-injectable, it executes a remote container against local files with elevated privileges, creating meaningful host-exposure risk if the image or workload is compromised.

Content

Scanner excerpt · server.py (reported line 153)May include surrounding context.

python
]

    try:
        proc = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
        output = proc.stdout + proc.stderr
    except subprocess.TimeoutExpired:
        return {"status": "error", "message": f"timeout after {timeout}s"}

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The user-facing tool descriptions and setup guide text are written entirely in Chinese, which effectively forces a specific language for interaction and setup. There is no opt-in, language selection, or justification that this skill is intentionally limited to a Chinese-speaking audience.

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 · server.py (reported line 260)May include surrounding context.

python
# 1. Docker
    try:
        ver = subprocess.check_output(["docker", "--version"], text=True, timeout=5).strip()
        lines.append(f"- Docker: 已安装 ({ver})")
    except Exception:
        lines.append("- Docker: **未安装** — 请先安装 Docker 和 nvidia-container-toolkit")

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 · server.py (reported line 268)May include surrounding context.

python
# 2. GPU
    try:
        out = subprocess.check_output(
            ["nvidia-smi", "--query-gpu=name,compute_cap,driver_version", "--format=csv,noheader"],
            text=True, timeout=10,
        ).strip()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The setup guide explicitly tells users to run a remote container with root privileges and host networking but provides no security warning or safer alternative. This increases the chance users will normalize an unnecessarily risky operational pattern outside the skill's controlled flow.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding

The setup guide instructs users to pull an image identified by a mutable latest-* tag rather than an immutable digest. That weakens supply-chain integrity because the content behind the tag can change over time, and this skill subsequently runs that image with elevated container privileges.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The description explicitly says the skill recognizes Chinese/English text, which is a language-specific capability stated without any user choice or justification for limiting language scope. Under the policy criteria, fixed language or locale constraints should either be optional for the user or clearly documented as region-specific.

Content

No source excerpt is available for this finding.

Rp1

Low
Category
MCP Rug Pull
Confidence
84% confidence
Finding

The installation instruction uses an unpinned Python package dependency, which allows future upstream releases of the mcp package to change behavior or introduce malicious code without any change to this skill. This creates a supply-chain risk during setup, especially because the package is used to run a local MCP server.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.