T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/convert.py:112
- Finding
- Stored HTML and JavaScript Injection in Generated Pages## Vulnerability Details **File Location**: `scripts/convert.py:49-54, 63-68, 72-79, 101-103, 112-128` **Vulnerability Type**: Unsanitized Markdown content and attribute injection **Risk Level**: High The converter places attacker-controlled Markdown content into an HTML document without first escaping or sanitizing it. Link destinations and code-fence language identifiers are also inserted into HTML attributes without contextual encoding. ### Vulnerable Code The ordinary paragraph path inserts the result of `process_inline_formatting()` directly into HTML: ```python # Normal paragraph text = process_inline_formatting(line) html.append(f'<p>{text}</p>') ``` Header and list content use the same unsafe formatting function: ```python # Headers if line.startswith('#'): level = len(line) - len(line.lstrip('#')) text = line.lstrip('#').strip() text = process_inline_formatting(text) html.append(f'<h{level}>{text}</h{level}>') i += 1 continue # Unordered lists if line.strip().startswith(('- ', '* ', '+ ')): if not in_list: in_list = True list_items = [] item_text = re.sub(r'^[\s\-\*\+]+', '', line).strip() item_text = process_inline_formatting(item_text) list_items.append(f'<li>{item_text}</li>') i += 1 continue ``` The inline formatter performs substitutions without HTML-escaping the original text. It also places an unrestricted link destination directly into an `href` attribute: ```python def process_inline_formatting(text): """Process inline markdown formatting""" # Bold text = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', text) text = re.sub(r'__(.+?)__', r'<strong>\1</strong>', text) # Italic text = re.sub(r'\*(.+?)\*', r'<em>\1</em>', text) text = re.sub(r'_(.+?)_', r'<em>\1</em>', text) ...[truncated 3374 chars]
- Remediation
- ## Remediation Suggestions 1. Replace the regular-expression converter with a maintained Markdown parser configured to disable raw HTML, or sanitize the parser output with a strict HTML allowlist. 2. Escape all untrusted source text before constructing HTML. Apply encoding appropriate to the destination context, distinguishing element text from attribute values. 3. Preserve Markdown formatting through parsed tokens rather than escaping text after HTML tags have already been introduced. 4. Validate link schemes explicitly. Permit only required schemes such as `https`, `http`, and optionally `mailto`; reject `javascript:`, `data:`, `vbscript:`, and unknown schemes. 5. HTML-escape both link labels and attribute values. 6. Restrict code-fence language identifiers to a safe pattern such as `^[A-Za-z0-9_-]+$`. Reject or discard values that do not match. 7. Add `rel="noopener noreferrer"` to every link using `target="_blank"`. 8. Consider adding a restrictive Content Security Policy to the generated template, for example one that disallows inline scripts and external resources. This should be defense in depth rather than a replacement for sanitization. 9. Add regression tests for raw script elements, event-handler attributes, `javascript:` links, quotes in link destinations, malicious code-fence identifiers, and malformed Markdown. 10. Clearly document whether raw HTML is intentionally supported. If it is required, process it with an allowlist sanitizer before inserting it into the template.
