T09 · Insecure Skill Coding Practices
- Location
scripts/generate.js:96- 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 generator 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 ...[truncated 3315 chars]- Remediation
View remediation
`, `"`, and `'`. 2. Escape every scalar value before inserting it into an HTML text context, including supplier fields, client fields, item names, units, notes, dates, and invoice type. 3. Replace manual string concatenation and chained `replace()` calls with a template engine that enables automatic escaping by default. 4. Keep trusted template fragments, such as generated table-row structure, separate from untrusted text values. 5. Validate fields according to strict schemas: - Dates must match the expected date format. - Invoice type should be selected from an allowlist. - Numeric fields must be finite integers within acceptable business limits. - Text fields should have reasonable length limits. 6. Disable JavaScript while rendering invoices if scripts are not required: ```js await page.setJavaScriptEnabled(false); ``` 7. Add a restrictive Content Security Policy to both templates, for example one that denies scripts and external connections. 8. Consider request interception in Puppeteer and reject all network requests not required for local invoice rendering. 9. Add tests using payloads containing closing tags, script elements, event-handler attributes, and malformed table markup to verify that they are rendered only as text. ]]>
