T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/generate.py:208
- Finding
- Stored Cross-Site Scripting Through Unsafe Topology Data Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py`, lines 208, 224-257, 284-285, 348, 455, and 564-575 **Vulnerability Type**: Stored cross-site scripting and unsafe HTML, SVG, CSS, and JavaScript generation **Risk Level**: High ### Vulnerable Code #### Unescaped identifiers in SVG attributes — line 208 ```python lines.append(f'<path class="{cls}" data-conn="{i}" data-src="{src_id}" data-tgt="{tgt_id}" d="{d}"/>') ``` #### Unescaped node IDs in generated SVG elements — lines 224-261 ```python if ntype == "orchestrator": return f'''<g data-nid="{nid}" data-name="{name}" data-desc="{subtitle}" class="orch-group" style="cursor:pointer"> <circle class="pulse-ring" cx="{x}" cy="{y}" r="{r}"/> <circle class="pulse-ring pr2" cx="{x}" cy="{y}" r="{r}"/> <circle class="pulse-ring pr3" cx="{x}" cy="{y}" r="{r}"/> <circle class="orch-outer" cx="{x}" cy="{y}" r="{r}"/> <circle class="orch-inner" cx="{x}" cy="{y}" r="{int(r*0.72)}"/> <text class="lbl-emoji" x="{x}" y="{y-13}" font-size="22">{emoji}</text> <text class="lbl-orch-name" x="{x}" y="{y+10}">{name}</text> <text class="lbl-orch-sub" x="{x}" y="{y+25}">{subtitle}</text> </g>''' elif ntype == "system": return f'''<g class="sys-node" data-nid="{nid}" data-name="{name}" data-desc="{subtitle}" transform="translate({x:.0f},{y:.0f})"> <circle class="sys-circle" r="{r}"/> <text class="lbl-emoji" font-size="17" y="-10">{emoji}</text> <text class="lbl-main" y="8">{name}</text> <text class="lbl-sub" y="20">{subtitle}</text> </g>''' elif ntype == "agent": return f'''<g class="agent-node" data-nid="{nid}" data-name="{name}" data-desc="{subtitle}" transform="translate({x:.0f},{y:.0f})"> <circle class="agent-circle" r="{r}"/> <text class="lbl-emoji" font-size="13" y="-7">{emoji}</text> <text class="lbl-main" font-size="10" y="7">{name}</text> <text class="lbl-sub" y="19">{subtitle}</text> </g>''' elif ntype == "human": re ...[truncated 6070 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Eliminate the `innerHTML` sink.** Construct the tooltip with DOM nodes and `textContent`: ```javascript function showTip(e, n, d) { clearTimeout(hideTimer); tip.replaceChildren(); var strong = document.createElement('strong'); strong.textContent = n; tip.appendChild(strong); if (d) { tip.appendChild(document.createTextNode(' — ' + d)); } tip.classList.add('show'); moveTip(e); } ``` 2. **Strictly validate node IDs and connection endpoints.** Enforce the documented identifier syntax and reject duplicate IDs: ```python ID_PATTERN = re.compile(r"^[a-z0-9_]+$") if not isinstance(n["id"], str) or not ID_PATTERN.fullmatch(n["id"]): raise ValueError("Node IDs must contain only lowercase letters, digits, and underscores") if n["id"] in node_ids: raise ValueError(f"Duplicate node ID: {n['id']}") ``` 3. **Apply context-aware HTML attribute encoding.** Every value inserted into an HTML or SVG attribute must use: ```python html_mod.escape(str(value), quote=True) ``` This must include node IDs, connection source and target IDs, titles, names, descriptions, and any other string-valued attributes. 4. **Validate numeric fields before generation.** Require `viewBox`, positions, radii, and `starCount` to be finite numeric values. Apply safe bounds, such as a nonnegative `starCount` with a reasonable maximum, to prevent script injection and resource exhaustion. 5. **Serialize all JavaScript values with `json.dumps`.** Never interpolate raw strings into JavaScript literals: ```python count = validate_star_count(bg_opts.get("starCount", 150)) color_js = json.dumps(validate_color(bg_opts.get("starColor", "rgba(200,214,224,0.3)"))) ``` 6. **Allowlist CSS and SVG values.** Parse color fields as supported hexadecimal, RGB, or RGBA formats. Reject values containing delimiters or unsupported CSS const ...[truncated 665 chars]
