T09 · Insecure Skill Coding Practices
Error
- Location
- templates/design-picker.html:890
- Finding
- Generated and User-Influenced Data Is Inserted Through innerHTML Without Runtime Sanitization<![CDATA[ ## Vulnerability Details **File Location**: `templates/design-picker.html:890-924` and `templates/design-picker.html:1269-1304` **Vulnerability Type**: DOM-based HTML injection and cross-site scripting **Risk Level**: High ### Vulnerable Code ```javascript var tokens = { "{{bg}}": bg, "{{fg}}": fg, "{{ac}}": pal.accent, "{{mt}}": pal.muted || pal.mid || al(fg, 0.4), "{{hf}}": tp.headline.family, "{{hw}}": tp.headline.weight, "{{bf}}": tp.body.family, "{{bw}}": tp.body.weight, "{{cr}}": mb.corners || "4px", "{{pad}}": mb.padding || "20px", "{{gap}}": mb.gap || "16px", "{{shadow}}": mb.shadow || "none", "{{sf}}": al(fg, 0.06), "{{g}}": al(fg, 0.06), "{{fg3}}": al(fg, 0.03), "{{fg6}}": al(fg, 0.06), "{{fg8}}": al(fg, 0.08), "{{fg15}}": al(fg, 0.15), "{{ac3}}": al(pal.accent, 0.03), "{{ac5}}": al(pal.accent, 0.05), "{{ac25}}": al(pal.accent, 0.25), "{{prompt_headline}}": (PROMPT && PROMPT.headline) || "Your Headline", "{{prompt_sub}}": (PROMPT && PROMPT.subline) || "A subline for your product.", }; var preview = arch.preview_html || ""; Object.keys(tokens).forEach(function (k) { preview = preview.split(k).join(tokens[k]); }); var tagHtml = [tp.headline.family, pal.name, CORNERS[mb.corners_index || 1].name] .map(function (t) { return '<span class="mood-token">' + t + "</span>"; }) .join(""); card.innerHTML = '<div class="mood-preview"><div style="transform:scale(0.38);transform-origin:top left;width:263.16%;min-height:263.16%;">' + preview + '</div></div><div class="mood-info"><div class="mood-name">' + mb.name + '</div><div class="mood-desc">' + mb.description + '</div><div class="mood-tokens">' + tagHtml + "</div></div>"; ``` The full-size preview repeats the same unsafe pattern: ```javascript var tokens = { "{{bg}}": bg, "{{fg}}": fg, "{{ac}}": ac, "{{mt}}": mt, "{{sf}}": al(fg, 0.06), "{{hf}}": t.headline.family, "{{hw}}": t.headline.weight, "{{bf}}": t.body. ...[truncated 3539 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Sanitize `preview_html` immediately before insertion using a well-maintained allowlist-based HTML sanitizer. 2. Permit only the minimum required elements and attributes. Explicitly reject: - `<script>`, `<iframe>`, `<object>`, `<embed>`, and active metadata elements. - All attributes beginning with `on`. - `javascript:`, `vbscript:`, and unsafe `data:` URLs. - SVG and MathML unless a strict, separately reviewed allowlist is implemented. - Form controls or navigation elements that are unnecessary for previews. 3. Use `textContent` for names, descriptions, labels, tags, and prompt text rather than concatenating them into HTML. 4. Construct static picker controls with DOM APIs such as `createElement`, `setAttribute`, and `appendChild`. 5. Validate colors, font weights, dimensions, corner radii, spacing, and shadow values against strict schemas before using them in inline styles. 6. Treat generated JSON as untrusted. Perform deterministic schema and security validation after generation rather than relying on instructions given to the generating agent. 7. Consider rendering architecture previews in sandboxed iframes with a restrictive `sandbox` attribute and an explicit Content Security Policy. 8. Add a Content Security Policy that blocks inline event handlers, restricts scripts to approved origins, and limits outbound connections. 9. Add regression tests containing event handlers, malformed attributes, dangerous URL schemes, SVG payloads, and closing-tag injection. ]]>
