# CSV formula injection in exports

User-controlled fields written to CSV exports that begin with =, +, -, @, or break quoting

_Area: Web injection and code execution. Seen in 3 disclosed reports; 2 confirmed bounties: $500 and $1,000; latest 2019-04-08. Updated 2026-10-23._

## How it works

A CSV export writes user-controlled text into a file that spreadsheet software later opens. Spreadsheets treat a cell beginning with `=`, `+`, `-`, or `@` as a formula, not text. If the exporter does not neutralize those leading characters, the user's input becomes an executable formula in the victim's spreadsheet. The broken assumption is that CSV is inert data; in practice the consumer (Excel, LibreOffice) reinterprets cell content as formulas and, via DDE/HYPERLINK, can reach external resources or run commands.

## Where it shows up

- Any export endpoint that echoes user-controlled fields: usernames, titles, labels, ticket names, trip names [E1](https://bugbountylibrary.com/r/h1%3A126109.md)[E2](https://bugbountylibrary.com/r/blog%3Ablog-zsec-uk-csvhub.md)[E3](https://bugbountylibrary.com/r/h1%3A118582.md).
- Fields accepting values starting with `=`, `+`, `-`, `@` without rejection or prefixing [E1](https://bugbountylibrary.com/r/h1%3A126109.md)[E2](https://bugbountylibrary.com/r/blog%3Ablog-zsec-uk-csvhub.md).
- Sanitizers that blacklist only some starters (e.g. `= + -`) but miss `@` or DDE `cmd|` [E2](https://bugbountylibrary.com/r/blog%3Ablog-zsec-uk-csvhub.md).
- Exporters that quote fields and escape `"` but do not neutralize formula content; locale separators like `;` inside quoted fields can break parsing [E3](https://bugbountylibrary.com/r/h1%3A118582.md).
- Multi-user contexts where one user's input lands in another user's downloaded file [E1](https://bugbountylibrary.com/r/h1%3A126109.md).

## How to review

Check the export writer, not just the input form. The invariant: every cell written to CSV must be forced to text — either reject/prefix leading `= + - @` (and tab/CR) at write time, or wrap and escape so the spreadsheet cannot re-parse content as a formula. Verify quoting handles embedded quotes, commas, and locale separators (`;`) so a crafted value cannot break out of its field [E3](https://bugbountylibrary.com/r/h1%3A118582.md). Confirm the sanitizer covers all trigger characters, including `@` and DDE patterns, not a partial blacklist [E2](https://bugbountylibrary.com/r/blog%3Ablog-zsec-uk-csvhub.md). Trace every user-controlled field that reaches an export sink [E1](https://bugbountylibrary.com/r/h1%3A126109.md).

## Variants seen

- Leading `=` in username field reaching admin CSV download [E1](https://bugbountylibrary.com/r/h1%3A126109.md).
- `@` trigger missed by blacklist, enabling DDE command invocation [E2](https://bugbountylibrary.com/r/blog%3Ablog-zsec-uk-csvhub.md).
- Quoted-field breakout via `";` re-enabling formula parsing despite quote escaping [E3](https://bugbountylibrary.com/r/h1%3A118582.md).

## Why fixes fail

E3 shows prior CSV-injection fixes (#72785, #111192) were bypassed: quote-escaping alone did not stop formula parsing when a locale separator broke the field. Blacklist-only sanitizers (E2) miss alternate triggers.

## Impact and severity

Led to data exfiltration via HYPERLINK and command execution (Meterpreter) on the victim's machine when the file is opened [E1](https://bugbountylibrary.com/r/h1%3A126109.md)[E2](https://bugbountylibrary.com/r/blog%3Ablog-zsec-uk-csvhub.md). Severity is high because it crosses a trust boundary: attacker input executes in another user's environment. Worse when exports are routinely opened by admins and when sanitizers are partial.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A126109.md
- E2: https://bugbountylibrary.com/r/blog%3Ablog-zsec-uk-csvhub.md
- E3: https://bugbountylibrary.com/r/h1%3A118582.md
