T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/drawio2html.py:52
- Finding
- Stored HTML and SVG Injection in Generated Diagram Pages<![CDATA[ ## Vulnerability Details **File Location**: `scripts/drawio2html.py`, lines 52, 182, 188-203, 211, 216-220, and 255 **Vulnerability Type**: Stored HTML/SVG injection leading to browser-side script execution **Risk Level**: High ### Vulnerable Code ```python # Line 52: attacker-controlled diagram name diagram_name = diagram_elem.get('name', 'Flowchart') if diagram_elem is not None else 'Flowchart' ``` ```python # Lines 182 and 188-203: attacker-controlled edge labels and style colors if e['value']: mid_idx = len(path_pts) // 2 lx = path_pts[mid_idx][0] ly = path_pts[mid_idx][1] - 8 svg_parts.append(f' <text x="{lx}" y="{ly}" text-anchor="middle" font-size="12" fill="#333">{e["value"]}</text>') # Draw vertices for v in vertices.values(): style = v['style'] x, y, w, h = v['x'], v['y'], v['w'], v['h'] fill = parse_color(style.get('fillColor')) or '#ffffff' stroke = parse_color(style.get('strokeColor')) or '#333333' is_rhombus = 'rhombus' in style is_rounded = 'rounded=1' in style or 'arcSize' in style font_weight = 'bold' if style.get('fontStyle') == '1' else 'normal' if is_rhombus: cx = x + w / 2 cy = y + h / 2 pts = f"{cx},{y} {x+w},{cy} {cx},{y+h} {x},{cy}" svg_parts.append(f' <polygon points="{pts}" fill="{fill}" stroke="{stroke}" stroke-width="2"/>') elif is_rounded: rx = 20 if 'arcSize=50' in str(style) else 8 svg_parts.append(f' <rect x="{x}" y="{y}" width="{w}" height="{h}" rx="{rx}" ry="{rx}" fill="{fill}" stroke="{stroke}" stroke-width="2"/>') else: svg_parts.append(f' <rect x="{x}" y="{y}" width="{w}" height="{h}" rx="4" ry="4" fill="{fill}" stroke="{stroke}" stroke-width="2"/>') ``` ```python # Line 211: attacker-controlled vertex label svg_parts.append(f' <text x="{cx}" y="{ty}" text-anchor="middle" font-size="13" font-weight="{font_weight}" fill="#1f2937">{line}</text>') ``` ```python # Lines 216-220 and 255: ...[truncated 3729 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Apply contextual escaping to every untrusted text value before embedding it in HTML or SVG: ```python import html safe_diagram_name = html.escape(diagram_name, quote=False) safe_node_text = html.escape(line, quote=False) safe_edge_text = html.escape(e['value'], quote=False) ``` 2. Escape values used in attributes with quote escaping enabled: ```python safe_attribute = html.escape(value, quote=True) ``` 3. Replace `parse_color()` with strict allowlist validation. Do not return arbitrary strings as CSS colors. At minimum, accept only explicitly supported formats: ```python COLOR_RE = re.compile(r'^#[0-9A-Fa-f]{6}$') def parse_color(value): if not value: return None if re.fullmatch(r'[0-9A-Fa-f]{6}', value): value = '#' + value return value if COLOR_RE.fullmatch(value) else None ``` If named, RGB, or RGBA colors are required, validate each format with dedicated parsers and bounded numeric components. 4. Prefer constructing the SVG and HTML through XML/HTML DOM builders or serializers rather than assembling markup with f-strings. A serializer will encode text nodes and attribute values according to their contexts. 5. Add a restrictive Content Security Policy as defense in depth, for example: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; script-src 'none'; connect-src 'none'; object-src 'none'; base-uri 'none'"> ``` Output encoding remains mandatory because CSP is not a substitute for correct escaping. 6. Add regression tests using diagram names, labels, and style values containing: - `<`, `>`, `&`, `"`, and `'` - Closing `</text>`, `</svg>`, and `</title>` sequences - `<script>` elements - SVG event-handler attributes such as `onload` - Invalid color values containing quotes or markup 7. Update `SKILL.md` to state that in ...[truncated 76 chars]
