Back to skill

Security audit

mm-output

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent document-to-poster tool, but its installer and HTML rendering pipeline create security risks that users should review before installing.

Review before installing. Use a sandbox or disposable environment, avoid running install.sh as root, replace curl-to-shell installation with verified packages, remove or pin the Git dependency, update vulnerable dependency pins, and only process documents you trust unless JavaScript is disabled and generated HTML is sanitized before conversion.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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)

T03 · Remote Payload Retrieval and Execution

Error
Location
install.sh:28
Finding
Unverified Remote Installer Is Piped Directly into a Shell<![CDATA[ ## Vulnerability Details **File Location**: `install.sh:28-35`; also documented in `SKILL.md:126-129` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: Critical ### Vulnerable Code `install.sh:28-35`: ```bash # Install UV install_uv() { if ! command -v uv &> /dev/null; then log_info "Installing UV..." curl -LsSf https://astral.sh/uv/install.sh | sh export PATH="$HOME/.cargo/bin:$PATH" fi log_success "UV version: $(uv --version)" } ``` `SKILL.md:126-129`: ```bash # Install UV curl -LsSf https://astral.sh/uv/install.sh | sh ``` ### Technical Analysis The installation process downloads a mutable script from an external URL and immediately passes its contents to `sh`. No version is pinned, and no checksum, signature, or other integrity verification is performed before execution. HTTPS provides transport protection but does not make the retrieved payload immutable. If the upstream website, release infrastructure, DNS resolution, certificate trust chain, or delivery account is compromised, the downloaded response can be changed after this Skill has been reviewed. Using Astral's documented UV domain reduces the likelihood that the URL is an intentional impersonation, but it does not eliminate the security weakness inherent in executing an unverified remote response. Installing UV is relevant to the declared functionality, but direct `curl | sh` execution exceeds the minimum safe privilege and integrity model required to install it. The downloaded script executes with all privileges of the user running `install.sh`. If the user invokes the installer as root because the same script later runs `apt-get`, the remote payload may receive full system privileges. ### Attack Path 1. An attacker compromises the upstream installer, hosting account, DNS/TLS infrastructure, or another component in the delivery chain. 2. The attacker replaces the expected UV installer response with a malicious s ...[truncated 935 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not pipe network responses directly into a shell. 2. Download a versioned installer artifact to a local file first: ```bash curl --fail --location --proto '=https' --tlsv1.2 \ --output uv-installer.sh \ https://example.invalid/versioned/uv-installer.sh ``` 3. Pin the expected release and verify a publisher-provided cryptographic signature or a separately obtained SHA-256 digest before execution: ```bash echo "<trusted-sha256> uv-installer.sh" | sha256sum --check - sh uv-installer.sh ``` 4. Prefer a trusted operating-system package or another package distribution mechanism that already performs signature and integrity verification. 5. Separate unprivileged user-level installation from privileged `apt-get` operations. Do not recommend running the complete project installer as root. 6. Update both `install.sh` and `SKILL.md` so the documented installation procedure follows the same verified process. 7. Record the reviewed UV version and expected digest in the repository to make installation reproducible. ]]>

T08 · Insecure Dependencies

Error
Location
requirements.txt:1
Finding
Mutable and Unpinned Git Dependency Permits Supply-Chain Code Substitution<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-3` **Vulnerability Type**: Insecure dependency source **Risk Level**: High ### Vulnerable Code ```text torch git+https://github.com/Hadlay-Zhang/marker.git marker-pdf ``` ### Technical Analysis The dependency declaration installs code directly from a Git repository without specifying a full commit hash or immutable release reference: ```text git+https://github.com/Hadlay-Zhang/marker.git ``` Consequently, installation resolves the repository's mutable default branch at install time. The code obtained by future users can differ from the code present when this Skill was audited. A compromised maintainer account, repository takeover, or malicious commit to the default branch could introduce arbitrary Python code or malicious package build hooks. This dependency is also inconsistent with `pyproject.toml`, which declares the pinned package: ```toml "marker-pdf==1.10.2", ``` The supplied `uv.lock.txt` likewise resolves `marker-pdf` version `1.10.2` from PyPI with a SHA-256 hash. Keeping both a mutable Git dependency and a pinned registry dependency creates divergent installation paths: users installing through `requirements.txt` receive a different and less reproducible trust model than users installing through the UV lock file. ### Attack Path 1. An attacker compromises the referenced GitHub repository, a maintainer account, or its default branch. 2. The attacker commits malicious package code or installation/build logic. 3. A user installs the project through `requirements.txt`. 4. The package manager clones the current repository state because no commit hash is pinned. 5. Malicious build hooks may execute during installation, or malicious module code executes when imported by the PDF parsing pipeline. 6. The attacker gains code execution with the privileges of the account performing installation or running the project. ### Impact Assessment Successful exploitation can result in ...[truncated 573 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the duplicate Git dependency and use the pinned `marker-pdf==1.10.2` registry package consistently. 2. Use one authoritative dependency manifest and commit the correctly named lock file so all installation paths resolve identical artifacts. 3. Require package hashes for deployment and continuous integration. 4. If the Git fork is strictly necessary, pin it to a reviewed full commit SHA: ```text marker @ git+https://github.com/Hadlay-Zhang/marker.git@<full-reviewed-commit-sha> ``` 5. Verify the pinned commit's provenance and review its build configuration before use. 6. Avoid mutable branch names and tags, since either may be moved after review. 7. Add automated dependency scanning and require review for changes to dependency source URLs, versions, hashes, and lock files. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
renderer_unit.py:107
Finding
Untrusted LLM-Generated HTML Is Executed in a JavaScript-Enabled Browser<![CDATA[ ## Vulnerability Details **File Location**: `renderer_unit.py:107-110`, `renderer_unit.py:120-123`, `renderer_unit.py:130-135`; execution sinks at `mm_output/converter.py:198-207` and `mm_output/converter.py:241-250` **Vulnerability Type**: Active-content injection and unsafe HTML rendering **Risk Level**: High ### Vulnerable Code Generated model output is written directly as HTML. For example, `renderer_unit.py:107-110`: ```python html_output_path = output_path / out_name html = self._postprocess_references(html, raw_text) html_output_path.write_text(self._postprocess_html(html), encoding='utf-8') print(f"[{self.name}] Successfully rendered HTML poster via LLM to: {html_output_path}") return str(html_output_path) ``` The same unsafe write occurs in the fallback and multi-template paths: ```python html_output_path = output_path / "poster_llm.html" html = self._postprocess_references(html, raw_text) html_output_path.write_text(self._postprocess_html(html), encoding='utf-8') ``` ```python template_html = Path(path).read_text(encoding='utf-8') html = self._render_via_llm_with_template( template_html, output_path, raw_text, figures, tables, web_images, model_id=model_id, temperature=temperature, max_tokens=max_tokens, max_attempts=max_attempts ) html = self._postprocess_references(html, raw_text) out_name = f"poster_llm__{Path(path).stem}.html" out_path = output_path / out_name out_path.write_text(self._postprocess_html(html), encoding='utf-8') ``` The resulting file is then opened in Chromium. `mm_output/converter.py:198-207`: ```python context_options = {"viewport": {"width": 1200, "height": 1600}} context = self._browser.new_context(**context_options) try: page = context.new_page() page.goto(f"file://{html_path}", wait_until="networkidle") ``` The PNG path performs the same operation at `mm_output/converter.py:241-250`: ```python context = self._browser.new_context( viewport={"width": viewport_size[0], "height": view ...[truncated 3425 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat all LLM output as hostile input. 2. Sanitize generated HTML using a strict allowlist before writing or rendering it. Remove scripts, iframes, objects, embeds, forms, event-handler attributes, unsafe SVG, and dangerous URL schemes. 3. Permit only the HTML elements and attributes required for static poster layout. 4. Disable JavaScript in the Playwright conversion context: ```python context = self._browser.new_context( viewport={"width": 1200, "height": 1600}, java_script_enabled=False, ) ``` 5. Block outbound requests during local conversion using Playwright routing. Permit only explicitly required local assets: ```python page.route( "**/*", lambda route: route.continue_() if route.request.url.startswith("file://") else route.abort() ) ``` 6. Bundle fonts, CSS, icons, and JavaScript locally instead of loading mutable CDN resources. If remote assets remain unavoidable, pin exact versions and apply Subresource Integrity where supported. 7. Add a restrictive Content Security Policy, for example disallowing scripts, frames, plugins, form submission, and remote connections. 8. Run Chromium with its normal sandbox enabled under a dedicated low-privilege account and an isolated temporary output directory. 9. Add tests containing prompt-injection documents and verify that scripts, event handlers, remote requests, iframes, and dangerous URLs are removed before conversion. 10. Consider rendering from a structured intermediate representation rather than allowing the LLM to generate arbitrary complete HTML. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (129)

Known Vulnerable Dependency: torch==2.9.1 — 4 advisory(ies): CVE-2025-3001 (PyTorch is vulnerable to memory corruption through its torch.lstm_cell function); CVE-2025-3000 (PyTorch is vulnerable to memory corruption through its torch.jit.script function); CVE-2026-4538 (A vulnerability was identified in PyTorch 2.10.0. The affected element is an unk) +1 more

Critical
Category
Supply Chain
Confidence
95% confidence
Finding
The project pins PyTorch to a version reported by the scanner as having multiple critical memory-corruption issues. In a skill that parses untrusted documents and uses ML tooling, a vulnerable native library materially increases risk because malformed model inputs or processing paths may trigger crashes or code-execution conditions in the dependency stack.

Known Vulnerable Dependency: transformers==4.57.6 — 9 advisory(ies): CVE-2026-4372 (HuggingFace transformers vulnerable to remote code execution); CVE-2026-1839 (HuggingFace Transformers allows for arbitrary code execution in the `Trainer` cl); CVE-2026-5241 (huggingface/transformers: Arbitrary Code Execution During Model Initialization i) +6 more

Critical
Category
Supply Chain
Confidence
97% confidence
Finding
The skill depends on a transformers version flagged for multiple arbitrary code execution vulnerabilities. This is especially dangerous here because the skill uses model-related packages in a document-processing pipeline, and model loading/configuration paths are a common attack surface when handling external assets or remote model artifacts.

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

Critical
Category
Data Flow
Content
for _ in range(max(1, attempts)):
                try:
                    r = requests.post(endpoint, headers=headers, json=body, timeout=60)
                    if r.status_code < 200 or r.status_code >= 300:
                        raise RuntimeError(f"HTTP {r.status_code}: {r.text[:500]}")
                    data = r.json()
Confidence
90% confidence
Finding
The HTTP endpoint is built from environment-controlled base_url and then used for outbound requests carrying the full document and assets. If an attacker can influence environment variables or deployment configuration, they can redirect all rendered content and API credentials to an arbitrary host, turning this into a data-exfiltration and credential-disclosure path.

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

Critical
Category
Data Flow
Content
last_err: Exception | None = None
        for _ in range(max(1, attempts)):
            try:
                resp = requests.post(endpoint, headers=headers, json=payload, timeout=120)
                if resp.status_code < 200 or resp.status_code >= 300:
                     raise RuntimeError(f"HTTP {resp.status_code}: {resp.text[:800]}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Known Vulnerable Dependency: torch==2.9.1 — 4 advisory(ies): CVE-2025-3001 (PyTorch is vulnerable to memory corruption through its torch.lstm_cell function); CVE-2025-3000 (PyTorch is vulnerable to memory corruption through its torch.jit.script function); CVE-2026-4538 (A vulnerability was identified in PyTorch 2.10.0. The affected element is an unk) +1 more

Critical
Category
Supply Chain
Confidence
97% confidence
Finding
The analysis indicates `torch==2.9.1` is affected by multiple published advisories, including memory-corruption issues. In a skill that ingests complex user-controlled files and may invoke native/ML processing pipelines, such flaws can lead to crashes, denial of service, or potentially code execution depending on reachable code paths.

Known Vulnerable Dependency: cryptography==46.0.5 — 11 advisory(ies): GHSA-537c-gmf6-5ccf (Vulnerable OpenSSL included in cryptography wheels); CVE-2026-69247 (cryptography: PKCS#7 EnvelopedData decryption exposes a Bleichenbacher oracle th); CVE-2026-69249 (python-cryptography: Duplicate self-signed intermediates can cause exponential p) +8 more

Critical
Category
Supply Chain
Confidence
98% confidence
Finding
cryptography==46.0.5 is pinned despite multiple reported advisories, including critical issues. This skill integrates several remote-service and document-processing libraries, so a vulnerable cryptographic foundation can affect authentication, certificate validation, encrypted content handling, or bundled OpenSSL behavior across the stack. Because many other dependencies rely on cryptography, compromise impact is broad.

Known Vulnerable Dependency: torch==2.9.1 — 4 advisory(ies): CVE-2025-3001 (PyTorch is vulnerable to memory corruption through its torch.lstm_cell function); CVE-2025-3000 (PyTorch is vulnerable to memory corruption through its torch.jit.script function); CVE-2026-4538 (A vulnerability was identified in PyTorch 2.10.0. The affected element is an unk) +1 more

Critical
Category
Supply Chain
Confidence
99% confidence
Finding
torch==2.9.1 is pinned despite multiple critical/high advisories, including memory corruption issues. This project heavily relies on ML/OCR/model execution against user-supplied files and likely loads models, tensors, and media-derived data, making low-level framework vulnerabilities particularly dangerous. In the worst case, these can lead to crashes, denial of service, or code execution in a high-privilege processing environment.

Known Vulnerable Dependency: transformers==4.57.6 — 9 advisory(ies): CVE-2026-4372 (HuggingFace transformers vulnerable to remote code execution); CVE-2026-1839 (HuggingFace Transformers allows for arbitrary code execution in the `Trainer` cl); CVE-2026-5241 (huggingface/transformers: Arbitrary Code Execution During Model Initialization i) +6 more

Critical
Category
Supply Chain
Confidence
99% confidence
Finding
transformers==4.57.6 is reported with multiple arbitrary code execution vulnerabilities, which is highly relevant in a project that depends on OCR and model tooling. Transformer ecosystems often load model configs, tokenizers, processors, and remote artifacts; when those inputs are untrusted, vulnerable versions can permit code execution during initialization or training-related flows. Because this skill’s functionality is deeply tied to model-driven parsing, this is one of the most dangerous findings in the file.

Credential Access

High
Category
Privilege Escalation
Content
# 完整安装(系统依赖 + Python 环境)
bash install.sh

# 安装完成后,编辑 .env 文件填入 API 密钥
vi .env
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 完整安装(系统依赖 + Python 环境)
bash install.sh

# 安装完成后,编辑 .env 文件填入 API 密钥
vi .env
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 完整安装(系统依赖 + Python 环境)
bash install.sh

# 安装完成后,编辑 .env 文件填入 API 密钥
vi .env
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 完整安装(系统依赖 + Python 环境)
bash install.sh

# 安装完成后,编辑 .env 文件填入 API 密钥
vi .env
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 完整安装(系统依赖 + Python 环境)
bash install.sh

# 安装完成后,编辑 .env 文件填入 API 密钥
vi .env
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 完整安装(系统依赖 + Python 环境)
bash install.sh

# 安装完成后,编辑 .env 文件填入 API 密钥
vi .env
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 完整安装(系统依赖 + Python 环境)
bash install.sh

# 安装完成后,编辑 .env 文件填入 API 密钥
vi .env
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 完整安装(系统依赖 + Python 环境)
bash install.sh

# 安装完成后,编辑 .env 文件填入 API 密钥
vi .env
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 完整安装(系统依赖 + Python 环境)
bash install.sh

# 安装完成后,编辑 .env 文件填入 API 密钥
vi .env
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill description materially overstates or misstates behavior relative to the referenced implementation, including parsing, rendering, and Gemini image-generation claims. Security reviewers and users may approve or invoke the skill under false assumptions, masking undeclared networked LLM use or other functionality that changes the risk profile.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The skill description materially overstates or misstates behavior relative to the referenced implementation, including parsing, rendering, and Gemini image-generation claims. Security reviewers and users may approve or invoke the skill under false assumptions, masking undeclared networked LLM use or other functionality that changes the risk profile.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The skill description materially overstates or misstates behavior relative to the referenced implementation, including parsing, rendering, and Gemini image-generation claims. Security reviewers and users may approve or invoke the skill under false assumptions, masking undeclared networked LLM use or other functionality that changes the risk profile.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill description materially overstates or misstates behavior relative to the referenced implementation, including parsing, rendering, and Gemini image-generation claims. Security reviewers and users may approve or invoke the skill under false assumptions, masking undeclared networked LLM use or other functionality that changes the risk profile.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill description materially overstates or misstates behavior relative to the referenced implementation, including parsing, rendering, and Gemini image-generation claims. Security reviewers and users may approve or invoke the skill under false assumptions, masking undeclared networked LLM use or other functionality that changes the risk profile.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill description materially overstates or misstates behavior relative to the referenced implementation, including parsing, rendering, and Gemini image-generation claims. Security reviewers and users may approve or invoke the skill under false assumptions, masking undeclared networked LLM use or other functionality that changes the risk profile.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill description materially overstates or misstates behavior relative to the referenced implementation, including parsing, rendering, and Gemini image-generation claims. Security reviewers and users may approve or invoke the skill under false assumptions, masking undeclared networked LLM use or other functionality that changes the risk profile.

Tp4

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
The skill description materially overstates or misstates behavior relative to the referenced implementation, including parsing, rendering, and Gemini image-generation claims. Security reviewers and users may approve or invoke the skill under false assumptions, masking undeclared networked LLM use or other functionality that changes the risk profile.

Static analysis

No suspicious patterns detected.