Back to skill

Security audit

Markdown to PDF

Security checks for vulnerabilities and agentic risk

Overview

This Markdown-to-PDF skill does what it claims, but its converter gives the PDF renderer broad local file access when processing Markdown, which users should review carefully.

Install only if you will convert Markdown files you trust, or run the converter in a restricted environment. Be cautious with Markdown from other people, because embedded HTML or resource links may cause wkhtmltopdf to access local files or network resources available to your account.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/convert.py:126
Finding
Untrusted Markdown Is Rendered with Local File Access and Network Resource Loading<![CDATA[ ## Vulnerability Details **File Location**: `scripts/convert.py`, lines 91 and 126–131 **Vulnerability Type**: Unsafe HTML rendering with excessive renderer capabilities **Risk Level**: High ### Vulnerable Code ```python # Convert Markdown to HTML html = markdown.markdown(md_content, extensions=['fenced_code', 'tables']) ``` ```python # Run wkhtmltopdf cmd = [ 'wkhtmltopdf', '--enable-local-file-access', tmp_path, output_path ] result = subprocess.run(cmd, capture_output=True, text=True) ``` ### Technical Analysis The Markdown input is converted to HTML without sanitizing raw HTML elements, attributes, scripts, or resource URLs. Python-Markdown preserves raw HTML by default, so attacker-controlled HTML can reach the generated temporary document. The document is then processed by `wkhtmltopdf` with `--enable-local-file-access`. JavaScript and network resource loading are not explicitly disabled. Consequently, crafted Markdown may cause the renderer to process local `file://` references or issue requests to attacker-selected, internal, or external URLs through elements such as images, frames, stylesheets, or scripts. There is no validation of URL schemes, target hosts, local paths, or resource types before rendering. The command uses an argument list rather than a shell command, so this is not shell-command injection; the vulnerability is the excessive file and network access granted to a renderer processing attacker-controlled content. ### Attack Path 1. An attacker supplies a Markdown document containing raw HTML or Markdown resource references. 2. The document references a sensitive local path, internal service, cloud metadata endpoint, or attacker-controlled server. 3. Python-Markdown preserves or generates the resource reference in the HTML document. 4. The application invokes `wkhtmltopdf` with local-file access enabled and without disabling JavaScript or external network access. 5. The renderer attempts to access the refe ...[truncated 1044 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--enable-local-file-access` unless local resource loading is strictly required. 2. Disable JavaScript explicitly with `--disable-javascript`. 3. Sanitize generated HTML using a maintained allowlist-based sanitizer. Remove raw scripts, frames, embedded objects, event-handler attributes, dangerous URI schemes, and other active content. 4. Validate all resource references and permit only required schemes and trusted destinations. Reject `file:`, loopback, link-local, private-network, and cloud metadata addresses. 5. Block outbound network access for the renderer at the operating-system or container level. 6. Run conversion in a dedicated sandbox or container under an unprivileged account with a read-only, minimal filesystem. 7. If local assets are necessary, copy validated assets into an isolated directory and restrict renderer access to that directory rather than the host filesystem. 8. Apply CPU, memory, execution-time, and output-size limits to the rendering process. 9. Keep the rendering engine patched and consider migrating from the archived or insufficiently maintained `wkhtmltopdf` stack to a maintained renderer with stronger sandboxing controls. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:20
Finding
Third-Party Dependencies Are Installed Without Version or Integrity Constraints<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 20–24 **Vulnerability Type**: Unpinned and non-reproducible third-party dependency installation **Risk Level**: Low ### Vulnerable Code ```bash pip install markdown pygments # You also need wkhtmltopdf installed: # macOS: brew install wkhtmltopdf # Ubuntu/Debian: sudo apt install wkhtmltopdf ``` ### Technical Analysis The installation instructions do not specify reviewed versions or integrity hashes for the Python packages. The system package instructions likewise do not identify a required renderer version or a verified source. As a result, installing the Skill at different times or in different environments can resolve to different dependency versions. A future compromised, vulnerable, or incompatible package release could therefore be installed without a corresponding review of this project. No evidence was found that the currently named packages are malicious, misspelled, or retrieved from an intentionally unsafe source. The finding concerns the absence of dependency pinning, integrity verification, and reproducible installation controls. ### Attack Path 1. A user follows the documented installation commands. 2. The package manager resolves mutable repository metadata and selects versions available at installation time. 3. If a selected release or repository is compromised, malicious installation behavior or vulnerable runtime code is introduced into the environment. 4. The compromised Python package is imported when `convert.py` starts, or the unsafe `wkhtmltopdf` executable is invoked during PDF conversion. 5. The dependency then executes with the permissions of the user running the Skill. ### Impact Assessment A compromised Python dependency could execute code during installation or import with the invoking user's privileges. A compromised or vulnerable renderer could execute unsafe behavior while processing attacker-controlled documents. The potential scope includes files, ...[truncated 313 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin all Python dependencies to reviewed versions in a requirements or lock file. 2. Use hash verification, such as `pip install --require-hashes -r requirements.txt`, for reproducible installations. 3. Document trusted package indexes and disable unintended fallback to untrusted repositories. 4. Specify a reviewed, supported renderer version and installation source. 5. Generate and maintain a software bill of materials for distributed releases. 6. Add automated dependency vulnerability scanning and a controlled update process. 7. Verify package signatures or repository metadata where the selected distribution mechanism supports them. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill documentation indicates capabilities that require reading local files and invoking shell commands, but it does not declare any tool scope such as permissions or allowed-tools. This creates an authorization gap where an agent may execute the skill with broader access than users or policy expect, increasing the risk of unintended file access or command execution.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
pip install markdown pygments
# You also need wkhtmltopdf installed:
# macOS: brew install wkhtmltopdf
# Ubuntu/Debian: sudo apt install wkhtmltopdf
```

## Usage
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The converter renders attacker-controlled Markdown into HTML and then calls wkhtmltopdf with --enable-local-file-access, allowing the renderer to load local files referenced by the generated HTML. If untrusted Markdown is processed, embedded file:// references or related local resource loads could expose sensitive local files in the generated PDF or to the rendering process, which is especially risky in an automated agent context that may have access to secrets or workspace data.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
output_path
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode != 0:
            print(f"❌ Error generating PDF: {result.stderr}")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.