T09 · Insecure Skill Coding Practices
- Location
scripts/generate.js:92- Finding
Unescaped Invoice Data Allows HTML and Script Injection During PDF Rendering
- Content
View full analysis
{ const amount = item.quantity * item.price; itemRows += ` ${idx + 1} ${item.name} ${item.unit} ${formatCurrency(item.quantity)} ${formatCurrency(item.price)} ${formatCurrency(amount)} `; }); const html = template .replace(/{{myCompanyName}}/g, myInfo.companyName || '') .replace(/{{myBusinessNumber}}/g, myInfo.businessNumber || '') .replace(/{{myCEO}}/g, myInfo.ceo || '') .replace(/{{myAddress}}/g, myInfo.address || '') .replace(/{{myPhone}}/g, myInfo.phone || '') .replace(/{{myEmail}}/g, myInfo.email || '') .replace(/{{clientName}}/g, client.name || '') .replace(/{{clientBusinessNumber}}/g, client.businessNumber || '') .replace(/{{clientCEO}}/g, client.ceo || '') .replace(/{{clientAddress}}/g, client.address || '') .replace(/{{clientPhone}}/g, client.phone || '') .replace(/{{issueDate}}/g, issueDate) .replace(/{{validUntil}}/g, validUntil) .replace(/{{itemRows}}/g, itemRows) .replace(/{{subtotal}}/g, formatCurrency(subtotal)) .replace(/{{vat}}/g, formatCurrency(vat)) .replace(/{{total}}/g, formatCurrency(total)) .replace(/{{notes}}/g, options.notes || ''); ``` The tax-invoice path has the same issue: ```js let itemRows = ''; itemList.forEach((item, idx) => { const amount = item.quantity * item.price; itemRows += ` ${issueDate} ${item.name} ${formatCurrency(item.quantity)} ${formatCurrency(item.price)} ${formatCurrency(amount)} ${options.notes || ''} `; }); const html = template . ...[truncated 3425 chars]- Remediation
View remediation
`, ``, attribute-breaking strings, and malicious CSS to verify that generated output renders them only as text. ]]>
