DEV Community

Tarun Jaswani
Tarun Jaswani

Posted on

Your 'Export to CSV' Button Is a Security Hole. CSV Injection Explained for Developers Who DiDn't Know This Existed.

You built an application that accepts user input — names, comments, form responses, whatever. Somewhere, there's an 'Export to CSV' or 'Download as Excel' button that lets an admin or user pull that data into a spreadsheet. Perfectly normal feature, built by thousands of apps. And if you're not sanitising that user input before it hits the export, you've built a weapon aimed at whoever opens the file.
https://github.com/tarunjaswani
CSV injection is an attack where a malicious user enters a crafted string into a data field — something that looks harmless in your application's UI, but becomes a live formula when opened in Excel or Google Sheets. The spreadsheet application executes it as code, not data. And the victim isn't your server; it's the person who clicked 'Export' and opened the file, usually an admin or internal team member.
https://github.com/tarunjaswani/CSV-Injection/tree/main
How It Actually Works
Spreadsheet applications like Excel and Google Sheets treat cell contents that begin with certain characters as formulas to execute. The dangerous characters are: = (equals), + (plus), - (minus), @ (at), and sometimes tab and carriage return. If a user enters a string beginning with one of these into a field your application stores and later exports to CSV, the spreadsheet application interprets it as a formula — not as the text string you intended it to be.
The classic demonstration: a user enters =cmd|'/C calc'!A1 as their 'name' in a form. Your app stores it as text. An admin exports the data to CSV and opens it in Excel. Excel sees the = at the start, interprets the rest as a DDE (Dynamic Data Exchange) command, and — if the user clicks through the warnings — executes a system command on the admin's machine.
More practically, the same mechanism can be used to exfiltrate data from the spreadsheet itself, make web requests to attacker-controlled servers (leaking information about who opened the file and from where), or trigger actions the opener didn't intend.
https://x.com/TJaswani7857
Why Developers Miss It
• It doesn't attack the server. Traditional security thinking focuses on protecting the server — SQL injection, XSS, authentication bypass. CSV injection bypasses the server entirely; the attack surface is the exported file and the software that opens it.
• The input looks harmless in the application. A string starting with '=' displays fine in a web UI, in a database, in an API response. It only becomes dangerous when it lands in a spreadsheet context — a context the developer wasn't thinking about when they built the input handler.
• It's not in the OWASP top 10 (as its own category). It's a form of injection, but it doesn't get the headline attention that SQLi or XSS do, so most security training skips it entirely.
How to Fix It

  1. Sanitise on output, not just on input. When writing data to a CSV export, prepend a single quote (') or a tab character before any cell value that begins with =, +, -, @, or tab. The single quote tells Excel to treat the cell as text, not a formula. This is the most reliable fix.
  2. Wrap values in double quotes and escape existing double quotes. Proper CSV quoting prevents some interpretation, though it alone doesn't stop all spreadsheet formula execution.
  3. Consider the export format. Exporting as .xlsx with a library that explicitly sets cell types to 'text' is safer than raw CSV, because you control how the spreadsheet interprets each cell.
  4. Never assume user input is safe for any context you haven't tested. Your input validation probably checks for SQL injection and XSS. It probably doesn't check for spreadsheet formula injection. Add it.
  5. Warn users about opening exported files from untrusted data sources. If your export contains user-supplied data from external or untrusted sources, a warning in the export or in the documentation is a defence-in-depth measure. ▸ https://medium.com/@rajkarar814/how-cybersecurity-can-change-the-world-dd4cd368c346 The Broader Point for Developers CSV injection is a specific example of a general principle: data is only safe in the context you validated it for. You validated user input for your web UI (hopefully). You validated it for your database queries (hopefully). But you didn't validate it for the spreadsheet that an admin will open after clicking 'Export' — because you weren't thinking about spreadsheets when you wrote the input handler. Every time data crosses a context boundary — from web to database, from database to CSV, from CSV to spreadsheet — the question 'is this safe in the new context?' needs to be asked again. The bug isn't in the CSV. It's in the assumption that safe-in-one-context means safe-in-all-contexts.

Your 'Export to CSV' button takes user input your app treated as text and hands it to a spreadsheet that treats it as code. The fix is a few lines of output sanitisation. The lesson is bigger: data that's safe in one context can be dangerous in the next, and the boundary between 'stored in a database' and 'opened in Excel' is a boundary most developers never think to guard.
— Tarun Jaswani

Top comments (0)