T09 · Insecure Skill Coding Practices
Error
- Location
- output_templates.py:16
- Finding
- Unescaped User-Controlled Content Enables HTML and Script Injection<![CDATA[ ## Vulnerability Details **File Location**: `output_templates.py:16-49` and `output_templates.py:83-129` **Vulnerability Type**: Unescaped HTML content injection / stored cross-site scripting **Risk Level**: High ### Vulnerable Code #### WordPress template (`output_templates.py:16-49`) ```python def wordpress_template(content, metadata, options): """WordPress HTML format with proper structure""" title = metadata.get('title', 'Untitled') author = metadata.get('author', 'Anonymous') date = metadata.get('date', datetime.now().strftime('%Y-%m-%d')) tags = metadata.get('tags', []) description = metadata.get('description', '') # Convert markdown-style formatting to HTML content = content.replace('\n\n', '</p>\n<p>') content = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', content) content = re.sub(r'\*(.+?)\*', r'<em>\1</em>', content) content = re.sub(r'`(.+?)`', r'<code>\1</code>', content) # Handle headers content = re.sub(r'^### (.+)$', r'<h3>\1</h3>', content, flags=re.MULTILINE) content = re.sub(r'^## (.+)$', r'<h2>\1</h2>', content, flags=re.MULTILINE) content = re.sub(r'^# (.+)$', r'<h1>\1</h1>', content, flags=re.MULTILINE) # Add image placeholders if requested if options.get('image_placeholders'): content = content.replace('[IMAGE]', '<!-- wp:image -->\n<figure class="wp-block-image"><img src="" alt=""/></figure>\n<!-- /wp:image -->') tags_html = ' '.join(f'<span class="tag">{html.escape(tag)}</span>' for tag in tags) return f"""<!-- wp:post-title /--> <!-- wp:post-meta --> <div class="post-meta"> <span class="author">By {html.escape(author)}</span> <span class="date">{html.escape(date)}</span> </div> <!-- /wp:post-meta --> <!-- wp:post-content --> <p>{content}</p> <!-- /wp:post-content --> ``` #### Email template (`output_templates.py:83-129`) ```python def email_template(content, metadata, options): """Email newslet ...[truncated 4320 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Escape all raw text before inserting it into HTML: ```python safe_content = html.escape(content, quote=True) ``` 2. Apply Markdown-style transformations only after escaping the input, so only markup generated by the application is treated as HTML: ```python safe_content = html.escape(content, quote=True) safe_content = safe_content.replace('\n\n', '</p>\n<p>') safe_content = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', safe_content) safe_content = re.sub(r'\*(.+?)\*', r'<em>\1</em>', safe_content) safe_content = re.sub(r'`(.+?)`', r'<code>\1</code>', safe_content) ``` 3. If intentional raw HTML support is required, use a maintained HTML sanitizer with a strict allowlist. Permit only necessary elements and attributes, and reject: - `script`, `iframe`, `object`, `embed`, and unsafe SVG or MathML elements; - attributes beginning with `on`, such as `onclick` and `onerror`; - `javascript:`, unsafe `data:`, and other dangerous URL schemes; - inline styles or other attributes that are not explicitly required. 4. Treat downstream platform sanitization as defense in depth rather than the primary control. 5. Add automated security tests covering: - `<script>` elements; - event-handler attributes such as `onerror`; - `javascript:` links; - SVG-based payloads; - malformed and nested HTML; - encoded payloads; - normal Markdown to verify that escaping does not break expected formatting. 6. Clearly distinguish trusted raw-HTML mode from the safe default if raw HTML must remain available. Require an explicit option to enable it and display a security warning. ]]>
