# CSV Injection: Formulas Hiding in a Converted File

- Author: FastBankConvert (https://www.fastbankconvert.com)
- Published: 2024-10-23
- Updated: 2024-10-23
- Category: CSV, JSON and text output
- Canonical: https://www.fastbankconvert.com/blog/csv-injection

> What CSV injection is: cells starting with = or + that run as formulas when opened, why payee text can trigger it, and how to neutralize it.
CSV injection happens when a text field in a CSV file starts with a character such as =, +, - or @, and a spreadsheet opening the file treats that cell as a formula instead of text. On a converted bank statement, payee or memo text written by someone else can carry the formula. Neutralize it by making such cells read as plain text.

## What is CSV injection?

CSV injection, also called formula injection, is what happens when data meant as text ends up running as a spreadsheet formula. A CSV file is plain text with no cell types, so spreadsheets decide for each cell whether it is a number, a date, text or a formula. A formula-looking cell gets calculated.

Most of the time that guess is harmless. A cell containing =1+1 shows 2. The problem is that a formula can do more than arithmetic. It can build links, pull in data from elsewhere, or display misleading values, and the person who opened the file never typed it. The text came from whoever wrote the data in the first place.

That is why the risk sits with files that mix your data with text from other people. Contact lists from a web form, survey answers, support tickets and bank transaction descriptions all contain strings that someone outside your organisation chose. The [OWASP page on CSV injection](https://community.owasp.org/attacks/CSV_Injection), from the open web security project, describes the attack and the standard defences.

CSV injection is not a flaw in the CSV format itself. The format simply has no way to say "this cell is text". The fix therefore has to happen either when the file is written or when it is opened.

## Which leading characters turn a CSV cell into a formula?

The characters that turn a CSV cell into a formula are the ones a spreadsheet treats as the start of a calculation: equals (=), plus (+), minus (-) and at (@). OWASP also lists tab, carriage return and line feed at the start of a field, and full-width versions of =, +, - and @ that some locales read as formulas too.

The table below shows example cell values, whether each would be read as a formula when the file is opened, and what the neutralized value looks like. The values are made up.

| Example cell value | Read as a formula? | Neutralized value |
| --- | --- | --- |
| COFFEE ROASTERS LTD | No | Unchanged |
| `=HYPERLINK(link, "Refund")` | Yes, shows a clickable link | `'=HYPERLINK(...)`, shown as text |
| +1 800 555 0100 HELPLINE | Yes, often an error or a number | '+1 800 555 0100 HELPLINE |
| -REVERSAL- CARD 2210 | Yes, usually an error | '-REVERSAL- CARD 2210 |
| @SHOPNAME ONLINE | Yes in some programs | '@SHOPNAME ONLINE |
| -45.10 in the amount column | Read as a number, which is correct | Unchanged |

The last row is the tricky one, and it gets its own section below. A minus at the start of an amount is exactly what you want. A minus at the start of a description is not.

Not every program treats all four characters the same way, and behaviour can change between versions. Treat any text field starting with one of them as suspect, rather than trying to remember which program handles which character.

## How payee text on a statement can trigger CSV injection

Payee text can trigger CSV injection because part of it is written by other people. When someone sends you a transfer, the reference or memo they type often prints on your statement. A converter copies that text faithfully into the description column, and if it starts with = or +, the converted CSV now holds a formula you never wrote.

Most of the time the cause is innocent. Phone numbers in merchant names start with +. Some banks print reversal or adjustment lines with a leading dash. Online shops sometimes start their name with @. Each of these produces an error cell or a strange value rather than an attack, but the data is still wrong when it opens.

The deliberate case is rarer, but it exists. Anyone who can send a small payment can choose the reference text, and that text lands in every statement export of the receiving account. A formula that builds a link labelled "Click to view refund" looks like part of the bank data when it sits in a description column.

Conversion errors add a third route. When a PDF's text layer does not line up with what is printed, characters from a neighbouring column, such as a minus or a plus from the amount, can end up stuck to the front of a description. [A misaligned PDF text layer](/blog/pdf-text-layer-misaligned) explains how that happens and how to spot it, and it is worth checking when descriptions start with odd symbols.

## Neutralizing CSV injection cells before the file is shared

To neutralize a CSV injection cell, make it start with something that is not a formula character, so the spreadsheet reads it as text. OWASP's standard advice is to wrap each field in double quotes, put a single quote at the start of the field, and double any double quotes inside it. Apply it to text columns only.

The single quote works because spreadsheets treat a leading apostrophe as "store this as text". The cell shows =HYPERLINK(...) as written, and nothing runs. OWASP notes two caveats worth knowing:

- **Quote-based fixes can fail after a save.** If someone opens the file in Excel, saves it, and opens it again, the protection may be lost. For Excel, OWASP suggests a tab character at the start of the field, inside the quotes, as a sturdier option.
- **Every fix changes the data.** The apostrophe or tab is now part of the value. A script reading the file later sees '=HYPERLINK, not =HYPERLINK, and has to know to strip it.

When you write the CSV yourself, from a script or a conversion step, a simple rule covers most cases:

1. Decide which columns are text, such as description, payee and memo.
2. In those columns, check whether a value starts with =, +, -, @, tab, carriage return or line feed.
3. If it does, put a single quote in front.
4. Quote the field and double any quotes inside it, as normal CSV quoting requires.
5. Leave number and date columns alone, after validating that they really hold numbers and dates.

If the destination is not a spreadsheet at all, the risk changes. A database import stores the text as text and never calculates it. [Moving PDF data into an Access database](/blog/pdf-to-access-database) is one route where formula text is inert, which makes it a safer place to inspect suspicious files.

## The cost of CSV injection fixes on real negative amounts

CSV injection fixes cost accuracy when they are applied to every cell instead of only text columns. A blanket rule that prefixes anything starting with a minus turns every negative amount into text, so the amount column no longer sums. Phone numbers, reference codes and reversal labels get changed too. Target the fix at the right columns.

Here is what goes wrong with a blanket fix on a bank statement:

- **Negative amounts become text.** -45.10 becomes '-45.10. It still looks negative, but SUM skips it, and the statement no longer balances.
- **Signed reference numbers change.** Some references legitimately start with a dash or a plus. Once prefixed, they no longer match the bank's records.
- **Round-trips break.** A file that is neutralized, edited and re-exported can pick up a second prefix, so ''=A1 appears where '=A1 used to be.

The safer pattern is to treat columns differently. Amount and balance columns should be validated as numbers: if a value parses as a number, it is safe to leave it as a number, minus and all. If it does not parse, reject the line or flag it, rather than escaping it. Text columns get the prefix rule. That keeps the money correct and the text harmless.

An Excel workbook sidesteps the question, because cells there carry their type and text stays text. FastBankConvert, which is getting ready to open, is built to convert statements to Excel as well as CSV or JSON; you can [get started](/get-started) to hear when it opens.

## Checking a CSV for injection before you open it

To check a CSV for injection safely, look at it as plain text before any spreadsheet calculates it. Open the file in a text editor, search for fields that start with a formula character, and if you need it in a spreadsheet, import it with the text columns set to Text rather than double-clicking it. Nothing calculates until you decide.

A pre-open checklist, for any CSV that contains text written by people outside your organisation:

- **Open it in a text editor first.** Notepad, TextEdit or any code editor shows the raw text and never runs a formula.
- **Search for risky starts.** Look for a comma or a quote directly followed by =, +, - or @, and for the same characters at the start of a line.
- **Separate amounts from text.** A minus right after a comma in the amount column is normal. A minus at the start of a description is worth a look.
- **Import, do not double-click.** Use Data > From Text/CSV in Excel and set description columns to Text, so their contents are never treated as formulas.
- **Do not click links inside cells** from a file you did not create, and do not accept prompts to enable external content.
- **Pick a format that cannot calculate** when the data is going to a presentation or a report. Pasting rows into a slide is safe, because slides do not run formulas; [putting a PDF table into PowerPoint](/blog/pdf-table-to-powerpoint) covers keeping the columns readable there.

None of this takes long on a single statement. It matters most when the same file passes through several hands, because the person who opens it last is rarely the person who knows where the text came from.
