Back to skill

Security audit

Markdown to PDF Advanced

Security checks for vulnerabilities and agentic risk

Overview

This Markdown-to-PDF skill is mostly purpose-aligned, but needs Review because it can auto-install unpinned packages at runtime and render document-controlled local or remote resources without tight controls.

Install only if you are comfortable with a document conversion skill that may change the Python environment when dependencies are missing. Prefer using it in an isolated virtual environment or container, preinstall pinned dependencies yourself, avoid running it as root, and do not process untrusted Markdown or CSS unless outbound network access and local file access are sandboxed.

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/md_to_pdf.py:173
Finding

Unrestricted Local and Remote Resource Loading During PDF Rendering

Content
View full analysis
Document {html_body} """ # Use custom CSS or default css_to_use = css_content if css_content else DEFAULT_CSS # Adjust page orientation if orientation == "landscape": css_to_use = css_to_use.replace("size: A4;", "size: A4 landscape;") # Convert to PDF font_config = FontConfiguration() html = HTML(string=html_content, base_url=str(Path(input_path).parent)) css = CSS(string=css_to_use, font_config=font_config) html.write_pdf(output_path, stylesheets=[css], font_config=font_config) ``` The custom CSS is also loaded without resource validation: ```python # Load custom CSS if provided css_content = None if args.css: if not os.path.exists(args.css): print(f"Warning: CSS file not found: {args.css}") else: with open(args.css, 'r', encoding='utf-8') as f: css_content = f.read() ``` ### Technical Analysis The converter passes Markdown-derived HTML and caller-selected CSS directly to WeasyPrint. No custom URL fetcher, URI allowlist, network restriction, or local-path containment check is configured. Python Markdown permits raw HTML in the source document under its normal behavior. Consequently, an untrusted document can introduce resource-loading elements such as images. Caller-controlled CSS can similarly contain resource directives such ...[truncated 2932 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/md_to_pdf.py:144
Finding

Automatic Installation of Unpinned Dependencies at Runtime

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The manifest and description understate operational behavior by implying straightforward conversion while also enabling package installation and overstating backend behavior. Misleading capability declarations are dangerous because users and orchestrators may approve or invoke the skill without understanding that it can modify the environment or rely on different execution paths than advertised.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Calling pip from inside the skill alters the host environment and executes package installation logic during normal use, creating a strong supply-chain and persistence risk. In agent or CI environments, this can unexpectedly pull remote code, modify shared interpreters, and leave lasting changes far beyond generating a PDF.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill demonstrates shell execution and file access in its documented usage, but it does not declare an explicit tool scope or permissions boundary. This can lead to over-privileged execution in agent environments, making unintended command execution or file access harder to govern and review.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The description says to use the skill for "any markdown-to-pdf conversion task," which is a broad natural-language trigger without clear boundaries or exclusion conditions. Although several specific trigger phrases are listed, this catch-all wording could overlap with many ordinary requests involving PDFs and markdown.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill claims no network is required, yet the documented support for remote images means conversion may fetch external resources. This creates a mismatch that can enable unexpected outbound requests, causing data leakage, privacy issues, or policy violations in restricted environments.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

bash
# Install system dependencies first (Ubuntu/Debian)
sudo apt-get install python3-dev libffi-dev libxml2-dev libxslt1-dev

# Then install Python packages
pip3 install weasyprint markdown Pygments

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

bash
# Install system dependencies first (Ubuntu/Debian)
sudo apt-get install python3-dev libffi-dev libxml2-dev libxslt1-dev

# Then install Python packages
pip3 install weasyprint markdown Pygments

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The troubleshooting section abruptly provides guidance in Chinese, while the rest of the document is in English, and there is no user opt-in or explanation for the locale change. This can violate language/locale policy expectations by forcing a specific language for part of the user-facing instructions.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
dnf install -y google-noto-emoji-color-fonts

# Ubuntu/Debian
sudo apt-get install fonts-noto-color-emoji

# 2. 刷新字体缓存让系统识别新字体
fc-cache -fv

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill advertises markdown-to-PDF conversion but also installs packages at runtime, which is an undisclosed capability expansion and environment modification. Hidden installation behavior erodes user trust and can be abused in automated agent contexts where users expect pure file conversion, not dependency changes or code retrieval from external repositories.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Automatic installation occurs without an explicit prompt or safety warning, so a user asking to convert a document may unknowingly trigger network access and environment mutation. That lack of informed consent is especially risky for an agent skill, because it may run unattended with privileges the user did not intend to grant for package management.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
96% confidence
Finding

This subprocess call invokes pip to modify the runtime environment during a document-conversion task, which is a risky side effect unrelated to the core operation. If run in a privileged or trusted automation context, it can install unexpected code from package indexes, change dependency state, and create a supply-chain execution path without explicit user approval.

Content

Scanner excerpt · scripts/md_to_pdf.py (reported line 148)May include surrounding context.

python
"""Try to install WeasyPrint automatically"""
    print("WeasyPrint not found. Attempting to install...")
    try:
        subprocess.check_call([
            sys.executable, "-m", "pip", "install", "--quiet",
            "weasyprint", "markdown", "Pygments"
        ])

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

python
cmd.extend(["-V", "geometry:landscape"])

    try:
        subprocess.run(cmd, check=True, capture_output=True, text=True)
        print(f"✓ PDF created: {output_path}")
        return True
    except subprocess.CalledProcessError as e:

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

Generating the PDF writes to the user-supplied output path, but the script does not disclose whether an existing file may be overwritten or otherwise affected. For file-writing operations, the rule asks for some visible disclosure, and this function only reports success after the write completes.

Content

No source excerpt is available for this finding.