T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/gen-report.py:14
- Finding
- Unescaped Report Data Allows HTML and Content Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gen-report.py`, lines 14-111 **Additional Affected Component**: `assets/report-template.html` **Vulnerability Type**: Unescaped HTML generation **Risk Level**: High ### Complete Code Snippet ```python data = json.loads(sys.argv[1]) if len(sys.argv) > 1 else {} def r(key, default='—'): return str(data.get(key, default)) replacements = { '{{DATE}}': r('date', '2026-04-08'), '{{WEEKDAY}}': r('weekday', '周三'), '{{TIME}}': r('time', '09:00'), '{{EC2_COUNT}}': r('ec2Count', '86'), '{{RDS_COUNT}}': r('rdsCount', '34'), '{{ELB_COUNT}}': r('elbCount', '28'), '{{COST_TOTAL}}': r('costTotal', '70,005'), '{{COST_DAILY}}': r('costDaily', '2,334'), '{{UNATTACHED_VOL}}': r('unattachedVol', '19'), '{{UNUSED_EIP}}': r('unusedEip', '1'), '{{LOW_CPU}}': r('lowCpu', '53'), '{{OLD_SNAP}}': r('oldSnap', '1'), '{{SP_UTIL_PCT}}': r('spUtilPct', '100'), '{{SP_COV_PCT}}': r('spCovPct', '51.5'), '{{RDS_RI_PCT}}': r('rdsRiPct', '34.6'), '{{EC_RI_PCT}}': r('ecRiPct', '18.4'), '{{NO_MFA}}': r('noMfa', '31/35'), '{{UNENC_EBS}}': r('unencEbs', '201/205'), '{{OPEN_SG}}': r('openSg', '17'), '{{OLD_KEYS}}': r('oldKeys', '13'), '{{S3_RISK}}': r('s3Risk', '4/19'), } for k, v in replacements.items(): html = html.replace(k, v) high_cpu = data.get('highCpu', [ {'name': 'kafka-prod-server-02', 'cpu': 50.6, 'level': 'orange'}, ]) cpu_html = '' for item in high_cpu: level = item.get('level', 'yellow') cpu_html += f'<div class="highlight-row"><span class="dot {level}"></span>{item["name"]}<span style="margin-left:auto;font-weight:600;color:{"#f87171" if level=="red" else "#fb923c" if level=="orange" else "#fbbf24"}">{item["cpu"]}%</span></div>' html = html.replace('{{HIGH_CPU_ITEMS}}', cpu_html) sp_details = data.get( 'spRiDetails', 'SP: $27.06/h 承诺 (3个活跃) · RDS RI: 31个实例 · Redis RI: 60个节点' ) html = html.replace('{{SP_RI_DE ...[truncated 3945 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace manual string concatenation and substitution with an auto-escaping template engine such as Jinja2. 2. Escape every text value with `html.escape(value, quote=True)` when a template engine cannot be used. 3. Apply validation according to output context: - Parse counts, costs, CPU values, and percentages as numeric types. - Constrain percentages to an expected range such as 0–100. - Allow-list CSS class values such as `red`, `orange`, `yellow`, `green`, and `blue`. - Reject unexpected object types and missing required fields. 4. Do not construct markup using attacker-influenced f-strings. 5. Add a restrictive Content Security Policy, for example by default-denying external content and disallowing scripts, frames, objects, and network connections. 6. Disable JavaScript in Puppeteer if the static report does not require it. 7. Treat all AWS metadata, tags, names, notification text, and generated summaries as untrusted input. 8. Add regression tests containing HTML metacharacters and active-markup payloads to verify that they are rendered as text. ]]>
