Back to skill

Security audit

Markdown Converter

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Markdown conversion skill, but users should avoid converting untrusted Markdown to HTML without sanitization.

Install only in a normal user environment or virtual environment, prefer pinned dependency versions if you maintain this skill, and do not use the HTML converter on Markdown from untrusted sources unless you sanitize the output or disable raw HTML/script content.

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_html.py:166
Finding
Stored HTML Injection in Generated Documents<![CDATA[ ## Vulnerability Details **File Location**: `scripts/md_to_html.py`, lines 166–178, with unsafe data reaching HTML output at lines 239–253, 288–290, 309, and 377–380 **Vulnerability Type**: Stored HTML and JavaScript injection **Risk Level**: High ### Vulnerable Code ```python def parse_inline(text): """Convert inline Markdown: bold, italic, code, links, images.""" # images text = re.sub(r'!\[([^\]]*)\]\(([^)]+)\)', r'<img src="\2" alt="\1" style="max-width:100%">', text) # links text = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'<a href="\2" target="_blank">\1</a>', text) # bold text = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', text) # italic text = re.sub(r'\*(.+?)\*', r'<em>\1</em>', text) # inline code text = re.sub(r'`([^`]+)`', r'<code>\1</code>', text) return text ``` The unescaped result is inserted into tables and document content: ```python for cell in table_rows[0]: html.append(f'<th>{parse_inline(cell)}</th>') for row in table_rows[1:]: html.append('<tr>') for cell in row: html.append(f'<td>{parse_inline(cell)}</td>') html.append('</tr>') ``` ```python output.append(f'<p>{parse_inline(line.strip())}</p>') ``` The Markdown title is also inserted into multiple HTML contexts without escaping: ```python title_match = re.search(r'^#\s+(.+)$', md_text, re.MULTILINE) title = title_match.group(1) if title_match else os.path.splitext(os.path.basename(input_path))[0] body = convert_md_to_html(md_text) html = HTML_TEMPLATE.format(title=title, content=body) ``` ### Technical Analysis The converter treats attacker-controlled Markdown as trusted HTML. `parse_inline()` performs regular-expression substitutions but never HTML-escapes ordinary text before returning it. As a result, raw HTML elements and event-handler attributes supplied in headings, paragraphs, list items, blockquotes, or table cells remain active in the generated document. Link destinations and image sour ...[truncated 2031 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. HTML-escape all untrusted plain text before inserting Markdown formatting: ```python import html safe_text = html.escape(text, quote=True) ``` 2. Avoid implementing Markdown parsing through regular-expression substitutions over untrusted text. Use a maintained Markdown library with raw HTML disabled and an explicit sanitization policy. 3. Escape values according to their output context: - Escape text placed inside HTML elements. - Escape quotes and metacharacters in attribute values. - Escape the title separately before inserting it into `<title>` and `<h1>`. 4. Validate link and image URL schemes using a URL parser. Permit only explicitly required schemes, such as `https`, `http`, and optionally `mailto`. Reject `javascript:`, unexpected `data:` URLs, embedded control characters, and obfuscated variants. 5. If limited raw HTML support is required, sanitize the rendered output with an allowlist-based HTML sanitizer. Permit only necessary elements and attributes, and remove scripts, event handlers, dangerous URLs, embedded frames, and active content. 6. Add automated regression tests covering: - Raw `<script>` and other active HTML in paragraphs and headings. - Quotes and angle brackets in link and image destinations. - Event-handler attributes. - Dangerous and mixed-case URL schemes. - Malicious content in titles, tables, lists, and blockquotes. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:22
Finding
Unpinned Third-Party Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 22–30 **Vulnerability Type**: Unpinned and non-reproducible dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash python3 -m pip install python-docx reportlab ``` ```bash python -m pip install python-docx reportlab ``` The documented fallback also installs the same mutable package versions: ```bash python3 -m pip install --user python-docx reportlab ``` ### Technical Analysis The installation instructions request `python-docx` and `reportlab` without version constraints or cryptographic hashes. Consequently, pip resolves whichever package versions are current on the user's configured package index at installation time. Although the package names match the modules used by the project and there is no evidence of typosquatting in the audited files, the installation is not reproducible. The effective dependency code can change after this Skill has been reviewed. Security therefore depends on the integrity of the configured index, its transport and trust settings, and the latest available package releases. If an index is compromised, a user has configured an untrusted additional index, or a future dependency release is malicious or compromised, installation or later import of that package can execute code outside the audited project. ### Attack Path 1. A user follows the dependency installation instructions in `SKILL.md`. 2. pip queries the package indexes configured in the user's environment. 3. Because no exact versions or hashes are specified, pip accepts the currently resolved distributions. 4. A compromised index, malicious mirror, unsafe index configuration, or compromised future release supplies altered dependency code. 5. The package executes with the privileges of the user running pip during installation or when imported by the conversion scripts. ### Impact Assessment The direct project code does not intentionally retrieve or execute remote payloads. ...[truncated 534 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin dependency versions that have been reviewed and tested, for example through a dedicated requirements file: ```text python-docx==<reviewed-version> reportlab==<reviewed-version> ``` 2. Generate and verify cryptographic hashes for every permitted distribution. Install with hash enforcement: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 3. Use a lock file or reproducible dependency-management workflow so transitive dependencies are also pinned. 4. Document the trusted package index explicitly and warn against untrusted mirrors or unnecessary extra indexes. 5. Regularly scan pinned dependencies for known vulnerabilities and update them through a controlled review process. 6. Prefer installation in an isolated virtual environment with ordinary user privileges rather than a system-wide or privileged Python environment. ]]>
Vulnerability Patterns
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code’s primary behavior is Markdown-to-DOCX conversion only. It does not contain any logic for producing PDF or HTML outputs, nor any orchestration for generating multiple formats from one input. The Chinese font support portion of the description is consistent with the code, since it sets East Asian fonts (PingFang SC). There are no obvious unrelated or dangerous extra capabilities, but the declared description materially overstates the conversion formats and workflow supported.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description presents a multi-format document conversion tool that outputs DOCX, PDF, and HTML. However, the provided script is solely an HTML converter: its usage, output path default, template, parsing logic, and final write operation all target HTML only. There is no code for DOCX creation, PDF rendering, external converters, or multi-output orchestration. While the script does include styled HTML and some CJK-friendly font settings, that is only a partial match to the description. Therefore the description materially overstates the skill's actual capabilities and primary behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The description advertises a multi-target document conversion skill producing DOCX, PDF, and styled HTML from Markdown. However, the provided code chunk is a single script explicitly named and documented as md_to_pdf.py, and its behavior is limited to generating a PDF from a Markdown input file. It parses headings, lists, tables, code blocks, and inline formatting, then builds a PDF with reportlab. The Chinese font support in the description is consistent with the code, but the core declared functionality is materially overstated: there is no code for Word export, no code for HTML export, and no orchestration for producing all formats together. Therefore the description does not accurately represent the actual behavior.

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding
The skill uses 'file_read' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding
The skill uses 'file_write' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
script_path = os.path.join(SCRIPT_DIR, script_name)
    cmd = [sys.executable, script_path] + list(args)
    print(f'  Running: {" ".join(cmd)}')
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f'  ERROR: {result.stderr.strip()}')
        return False
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The manifest describes a skill that converts Markdown to Word, PDF, and styled HTML in one shot, but this script exclusively implements DOCX generation via python-docx. There is no code for PDF rendering or HTML output, so the implemented behavior is materially narrower than the advertised capability.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The generated HTML hard-codes `lang="zh-CN"`, which imposes a specific language/locale on all output regardless of the input document or user preference. This is a natural-language locale policy issue because the script does not offer any language choice or document that the tool is intentionally region-specific.

Static analysis

No suspicious patterns detected.