T09 · Insecure Skill Coding Practices
Error
- Location
- src/converter.py:387
- Finding
- Unsanitized HTML and Title Injection into the wkhtmltopdf Rendering Context<![CDATA[ ## Vulnerability Details **File Location**: `src/converter.py:387-423`, `src/converter.py:451-470`, and `src/converter.py:500-515` **Vulnerability Type**: Untrusted active HTML injection and unsafe document rendering **Risk Level**: High ### Vulnerable Code ```python def markdown_to_html(self, markdown_text: str, title: str = 'Document') -> str: """ Convert markdown to HTML. Args: markdown_text: Markdown text to convert. title: Document title. Returns: HTML string. """ # Replace emoji with PDF-compatible colored text labels markdown_text = replace_emoji_for_pdf(markdown_text, use_color=True) # Convert markdown to HTML with extensions html = markdown.markdown( markdown_text, extensions=[ 'extra', 'codehilite', 'toc', 'tables', 'fenced_code', 'nl2br' ] ) css = self.generate_css() # Add HTML structure with theme html_template = f"""<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{title}</title> <style>{css}</style> </head> <body> {html} </body> </html> """ return html_template ``` The resulting HTML is then passed directly to the rendering engine: ```python pdfkit.from_string( html, str(output_path), options={ 'page-size': page_size, 'margin-top': margin, 'margin-right': margin, 'margin-bottom': margin, 'margin-left': margin, 'encoding': 'UTF-8', 'no-outline': None, 'print-media-type': None } ) ``` ```python imgkit.from_string( html, str(output_path), options={ 'width': width, 'format': 'png', 'quality': quality } ) ``` ### Technical Analysis The Markdown input is converted to HTML without an HTML sanitization stage. Python Markdown can preserve raw HTML ...[truncated 3033 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Sanitize generated HTML with a strict allowlist before invoking the renderer. Permit only document-formatting elements and safe attributes. 2. Escape the document title with `html.escape(title, quote=True)` before inserting it into the template. 3. Explicitly disable JavaScript in both PDF and image rendering options unless it is strictly required. 4. Block or remove dangerous URL schemes, including `file:`, `javascript:`, and unexpected `data:` resources. 5. Disable local-file access explicitly and allow it only for narrowly defined asset directories if needed. 6. Prevent external network access during conversion, or route requests through an allowlist-based proxy. 7. Run `wkhtmltopdf` in a sandbox or container with: - No credentials or environment secrets. - A read-only filesystem except for a dedicated output directory. - No access to cloud metadata endpoints or internal networks. - A non-privileged user and strict resource limits. 8. Add security tests covering raw `<script>`, `<iframe>`, remote images, loopback URLs, internal addresses, `file:` URLs, event-handler attributes, and title-element breakout attempts. ]]>
