T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/accessibility_checker.py:347
- Finding
- Stored HTML Injection in Accessibility Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/accessibility_checker.py`, lines 35–36, 100–101, 140–141, 174–175, 215–216, and 347–458 **Vulnerability Type**: Stored HTML injection through unescaped Figma metadata **Risk Level**: High ### Vulnerable Code Untrusted file and node metadata is copied from the Figma API into report data: ```python results = { 'file_key': file_key, 'file_name': file_data.get('name', 'Unknown'), 'wcag_level': level, 'timestamp': time.time(), 'compliance_score': 0, 'issues': [], 'summary': {} } ``` Issue records also retain attacker-controlled node names and text content: ```python results['issues'].append({ 'type': 'text_size', 'severity': 'error', 'message': f'Text too small: {font_size}px (minimum: {min_size}px)', 'node_id': node.get('id'), 'node_name': node.get('name', ''), 'wcag_criterion': '1.4.4', 'details': { 'font_size': font_size, 'min_size': min_size, 'characters': node.get('characters', '')[:50] } }) ``` These values are subsequently interpolated directly into an HTML document: ```python html = f"""<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Accessibility Report - {results['file_name']}</title> ``` ```python for issue in results['issues']: severity_class = issue['severity'] html += f""" <div class="issue {severity_class}"> <h3>{issue['type'].replace('_', ' ').title()}: {issue['message']}</h3> <span class="wcag-criterion">WCAG {issue['wcag_criterion']}</span> <div class="node-info"> <strong>Element:</strong> {issue.get('node_name', 'N/A')} (ID: {issue.get('node_id', 'N/A')}) </div> """ if 'details' in issue and issue['details']: html += "<div style='margin-top: 10px;'><strong>Details:</strong><ul>" for key, value in issu ...[truncated 2407 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Escape every dynamic value before inserting it into HTML: ```python from html import escape safe_file_name = escape(str(results.get('file_name', 'Unknown')), quote=True) safe_node_name = escape(str(issue.get('node_name', 'N/A')), quote=True) safe_node_id = escape(str(issue.get('node_id', 'N/A')), quote=True) safe_message = escape(str(issue.get('message', '')), quote=True) safe_value = escape(str(value), quote=True) ``` 2. Prefer a template engine such as Jinja2 with automatic escaping enabled instead of building HTML through string concatenation. 3. Validate internal enumerated fields such as severity, issue type, and WCAG level against explicit allowlists before using them in markup or CSS class attributes. 4. Add a restrictive Content Security Policy to generated reports, for example: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:;"> ``` 5. Avoid inline event-capable markup and do not enable scripts in static reports. 6. Add regression tests using malicious file names, node names, IDs, and text values to verify that payloads are rendered as text rather than interpreted as HTML. ]]>
