T09 · Insecure Skill Coding Practices
- Location
scripts/analyze_session.py:221- Finding
Stored HTML Injection Through Unescaped Skill Names
- Content
View full analysis
Vulnerability Details
File Location:
scripts/analyze_session.py:221-223, 577-603
Vulnerability Type: Stored HTML injection caused by unsafe output encoding
Risk Level: HighVulnerable Code
Skill names are read from untrusted JSONL tool-call arguments:
python skill_name = args.get("skill") or args.get("name") if skill_name and self.is_valid_skill_name(skill_name): return skill_name.lower()The resulting value is inserted directly into two HTML contexts:
python for skill_name, data in results["skills"].items(): rate_class = 'high' if data['成功率'] >= 90 else 'medium' if data['成功率'] >= 70 else 'low' html += f""" <tr> <td><strong>{skill_name}</strong></td> <td>{data['调用次数']:,}</td> <td>{data['输入tokens']:,}</td> <td>{data['输出tokens']:,}</td> <td>{data['缓存读取tokens']:,}</td> <td><strong>{data['总tokens']:,}</strong></td> <td>{data['缓存命中率']:.1f}%</td> <td class="success-rate {rate_class}">{data['成功率']:.0f}%</td> </tr> """ html += """ </tbody> </table> <h2>📋 详细分析</h2> """ for skill_name, data in results["skills"].items(): html += f""" <div class="skill-detail"> <h3>{skill_name}</h3>Technical Analysis
Session JSONL files are input data and therefore cannot be trusted. A skill name may be obtained from the
skillornameproperty of aSkilltool call. Althoughis_valid_skill_name()performs format-oriented checks, those checks do not provide contextual HTML sanitization or encoding. In particular, accepted values are not constrained to a safe alphanumeric grammar and can contain HTML metacharacters if they otherwise meet the validation rules.to_html()subsequently interpolates the skill name into table-cell and heading content without HTML escaping. An attacker-controlled value can therefore terminate th ...[truncated 1495 chars]- Remediation
View remediation
Remediation Suggestions
-
Escape every dynamic text value before inserting it into HTML:
python from html import escape safe_skill_name = escape(str(skill_name), quote=True)Use
safe_skill_namein both the table cell and heading. -
Prefer an HTML templating engine with automatic escaping enabled rather than constructing the document through formatted string concatenation.
-
Enforce a strict skill-name grammar at the trust boundary, for example:
python re.fullmatch(r"[A-Za-z][A-Za-z0-9_-]*", name)Strict validation is defense in depth and must not replace context-appropriate output encoding.
-
Apply HTML escaping consistently to all future values originating from session files, including tool names and any additional metadata added to reports.
-
Add regression tests containing payloads with tags, event handlers, quotes, ampersands, and angle brackets. Verify that generated reports contain encoded text such as
<and do not create executable DOM elements. -
Consider applying a restrictive Content Security Policy to generated reports, such as disallowing scripts, as an additional mitigation.
-
