Back to skill

Security audit

pandoc-convert

Security checks for vulnerabilities and agentic risk

Overview

This document-conversion skill is mostly coherent, but needs review because its Pandoc access is broad enough to run local code through Pandoc filters.

Install only if you trust the documents and conversion options being used. Avoid accepting `--filter`, `--lua-filter`, or other unreviewed Pandoc options from untrusted prompts or files, and require explicit approval before running the installer with `--yes`.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/convert.sh:142
Finding

Unrestricted Pandoc Options Permit Arbitrary Filter Execution

Content
View full analysis

Vulnerability Details

File Location: scripts/convert.sh, lines 142-152
Vulnerability Type: Unrestricted forwarding of execution-capable command-line options
Risk Level: High

bash
      --)
          shift
          while [ "$#" -gt 0 ]; do
              pandoc_args+=("$1")
              shift
          done
          ;;
      --*)
          pandoc_args+=("$1")
          validate_args+=("$1")
          shift
          ;;

Technical Analysis

The wrapper forwards every unrecognized long option directly to Pandoc. It also forwards every argument following -- without validation. Although the final Pandoc invocation uses a Bash array and is therefore not directly vulnerable to shell metacharacter injection, Pandoc itself exposes execution-capable options.

In particular, Pandoc supports --filter and --lua-filter. A filter can be an executable program or a Lua script, and Pandoc executes it during document processing. Neither the conversion wrapper nor validate.sh rejects these options.

Consequently, the wrapper's prerequisite validation does not form a security boundary. An attacker who can influence conversion arguments and provide or reference a local filter can cause arbitrary code to run with the privileges of the Agent process.

The broad Bash(pandoc *) permission declared in SKILL.md also allows direct Pandoc invocation and should be narrowed as part of the same hardening effort.

Attack Path

  1. An attacker places a malicious executable or Pandoc Lua filter in an accessible project or temporary directory.
  2. The attacker requests a document conversion containing an option such as --lua-filter payload.lua or --filter ./payload.
  3. convert.sh treats the option as an unknown --* argument and adds it to pandoc_args.
  4. The associated option value is also added to the Pandoc argument array.
  5. validate.sh does not reject the execution-capable option.

...[truncated 683 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace the generic --* branch with an explicit allowlist of supported, non-executable Pandoc options.
  2. Reject unknown options with a clear error instead of forwarding them.
  3. Remove unrestricted forwarding of arguments after --, or apply the same strict allowlist to those arguments.
  4. Explicitly deny at least --filter, --lua-filter, and any other Pandoc option that loads code, invokes external programs, or reads configuration from an uncontrolled location.
  5. Ensure validate.sh applies the same option policy so validation and execution cannot interpret arguments differently.
  6. Narrow or remove the Bash(pandoc *) permission in SKILL.md; permit only hardened wrapper commands and narrowly scoped format-discovery operations where needed.
  7. Add negative tests demonstrating that execution-capable and unknown options are rejected.
  8. If filters are required in the future, accept only administrator-approved filters from a fixed, trusted directory and verify their canonical paths before execution.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/batch_convert.py:185
Finding

Insufficient Escaping Allows Markdown Report Content Injection

Content
View full analysis

Vulnerability Details

File Location: scripts/batch_convert.py, lines 185-187
Vulnerability Type: Markdown injection through untrusted report fields
Risk Level: Low

python
    for item in results:
        error = item.get("stderr", "").replace("|", "\\|")
        lines.append(f"| {item['status']} | {item['attempts']} | `{item['input']}` | `{item['output']}` | {error} |")

Technical Analysis

The Markdown report incorporates filenames, output paths, and Pandoc error output without context-appropriate escaping. Only pipe characters in stderr are escaped. Input and output paths are surrounded by single backticks, but embedded backticks and line breaks are not escaped. Error text is not placed in a code span and can contain active Markdown or HTML.

On filesystems that permit backticks and newline characters in filenames, an attacker-controlled filename can terminate the intended code span or table row. Pandoc diagnostics may also include attacker-influenced document content or filenames. Crafted values can therefore inject links, images, HTML, headings, or misleading rows into the generated report.

Attack Path

  1. An attacker supplies a supported document with a filename containing backticks, line breaks, or Markdown syntax, or causes Pandoc to emit attacker-influenced diagnostic text.
  2. Batch conversion fails or otherwise records the attacker-controlled value in a result.
  3. write_markdown_report inserts the value directly into the Markdown table with incomplete escaping.
  4. A user opens the generated report in a Markdown renderer.
  5. The injected content is rendered as active Markdown or HTML rather than inert report data.
  6. If the payload embeds a remote image or similar resource and the renderer permits remote loading, the viewer may make a request to an attacker-controlled server.

Impact Assessment

Exploitation can alter the visual meaning of the generated report, conceal or f ...[truncated 382 chars]

Remediation
View remediation

Remediation Suggestions

  1. Apply a dedicated Markdown-table escaping function to every dynamic field, including input paths, output paths, status values, and diagnostics.
  2. Normalize carriage returns and line feeds to spaces or visible escaped sequences so values cannot create additional table rows.
  3. Escape pipes, backslashes, backticks, and HTML-sensitive characters according to the destination context.
  4. Prefer fenced plain-text blocks for diagnostics instead of inserting arbitrary stderr directly into table cells.
  5. Consider generating the report through a Markdown library that safely serializes table cells.
  6. Keep the JSON report as the preferred machine-readable artifact and ensure consumers render its values as text.
  7. Add tests using filenames and diagnostics containing pipes, backticks, newlines, HTML tags, Markdown links, and image syntax.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description presents the skill primarily as a Pandoc-based document conversion tool with broad conversion and document-processing features. The actual code does not perform any document conversion or Pandoc invocation beyond checking pandoc --version after installation. Instead, it serves as an installer/recommender for Pandoc using package managers such as Homebrew, Conda, apt-get, dnf, and pacman. One small part of the description—'Pandoc installation help' and some PDF engine troubleshooting context—is consistent with the script, but the code chunk materially fails to implement the main declared purpose. Therefore this is a description/behavior mismatch.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Use `scripts/convert.sh` when the user gives one input file or asks for one output.

Lp1

High
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The script launches an external shell process (bash convert.sh), which is a shell-execution capability not reflected in the declared permissions. In an agent skill context, undisclosed shell access is more dangerous because it expands the trust boundary beyond simple document conversion and may enable unexpected command execution through downstream scripts or tools.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The script launches an external shell process (bash convert.sh), which is a shell-execution capability not reflected in the declared permissions. In an agent skill context, undisclosed shell access is more dangerous because it expands the trust boundary beyond simple document conversion and may enable unexpected command execution through downstream scripts or tools.

Content

No source excerpt is available for this finding.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · scripts/install_pandoc.sh (reported line 56)May include surrounding context.

sh
INSTALL_CMD="conda install -c conda-forge pandoc"
    MANAGER_NOTE="Conda detected."
elif command -v apt-get >/dev/null 2>&1; then
    INSTALL_CMD="sudo apt-get update && sudo apt-get install -y pandoc"
    MANAGER_NOTE="apt-get detected."
elif command -v dnf >/dev/null 2>&1; then
    INSTALL_CMD="sudo dnf install -y pandoc"

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

python
while attempts <= retries:
        attempts += 1
        command = ["bash", str(convert_script), str(input_file), "-o", str(output_file), *common_args]
        last_result = subprocess.run(command, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        if last_result.returncode == 0:
            return {
                "input": str(input_file),

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 · scripts/install_pandoc.sh (reported line 56)May include surrounding context.

sh
INSTALL_CMD="conda install -c conda-forge pandoc"
    MANAGER_NOTE="Conda detected."
elif command -v apt-get >/dev/null 2>&1; then
    INSTALL_CMD="sudo apt-get update && sudo apt-get install -y pandoc"
    MANAGER_NOTE="apt-get detected."
elif command -v dnf >/dev/null 2>&1; then
    INSTALL_CMD="sudo dnf install -y pandoc"

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 · scripts/install_pandoc.sh (reported line 59)May include surrounding context.

sh
INSTALL_CMD="conda install -c conda-forge pandoc"
    MANAGER_NOTE="Conda detected."
elif command -v apt-get >/dev/null 2>&1; then
    INSTALL_CMD="sudo apt-get update && sudo apt-get install -y pandoc"
    MANAGER_NOTE="apt-get detected."
elif command -v dnf >/dev/null 2>&1; then
    INSTALL_CMD="sudo dnf install -y pandoc"

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 · scripts/install_pandoc.sh (reported line 62)May include surrounding context.

sh
INSTALL_CMD="conda install -c conda-forge pandoc"
    MANAGER_NOTE="Conda detected."
elif command -v apt-get >/dev/null 2>&1; then
    INSTALL_CMD="sudo apt-get update && sudo apt-get install -y pandoc"
    MANAGER_NOTE="apt-get detected."
elif command -v dnf >/dev/null 2>&1; then
    INSTALL_CMD="sudo dnf install -y pandoc"

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code creates parent directories and writes the converted output file, and it also passes through options such as --extract-media that can write additional files. Although these behaviors are part of conversion, the script provides no explicit user-facing disclosure at execution time beyond generic usage text, so users are not warned that running it will create or overwrite filesystem content.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.