T09 · Insecure Skill Coding Practices
- Location
scripts/invoice_gen.py:94- Finding
Unescaped User-Controlled Data in Generated HTML Invoices
- Content
View full analysis
str: subtotal, discount, tax, total = build_totals(job) currency = job.get("currency", "USD") f = job.get("from", {}) t = job.get("to", {}) rows = "".join( f"{i['description']}{i['quantity']}{currency} {i['rate']:,.2f}{currency} {i['quantity'] * i['rate']:,.2f}" f"" f"" for i in job["items"] ) extra_rows = "" if discount: extra_rows += f"Discount-{currency} {discount:,.2f}" if job.get("tax_rate_pct"): extra_rows += f"Tax ({job['tax_rate_pct']}%){currency} {tax:,.2f}" return f""" Invoice {job.get('invoice_number', '')} body {{ font-family: -apple-system, Helvetica, Arial, sans-serif; max-width: 720px; margin: 40px auto; color: #1a1a1a; }} table {{ width: 100%; border-collapse: collapse; margin-top: 16px; }} th, td {{ text-align: left; padding: 8px; border-bottom: 1px solid #ddd; }} th {{ background: #f5f5f5; }} .total {{ font-size: 1.2em; font-weight: bold; }} .meta {{ color: #555; }}Invoice {job.get('invoice_number', '')}
Date: {job.get('date', datetime.now().date().isoformat())} | Due: {job.get('due_date', 'On receipt')}
From: {f.get('name', '')}
{f.get('email', '')}
{f.get('address', '')}Bill To: {t.get('name', '')}
DescriptionQtyRateAmount {rows} {extra_rows}
{t.get('email', '')}
{t.get('address', '')}- Remediation
View remediation
`, `&`, single quotes, and double quotes are encoded and cannot create elements or attributes. 6. Consider adding a restrictive Content Security Policy to generated HTML as defense in depth. Output escaping remains mandatory because a policy alone does not prevent deceptive markup injection. ]]>
