Skip to content

Neutralize spreadsheet formula characters in CSV export - #916

Open
carfeii wants to merge 1 commit into
sharkdp:masterfrom
carfeii:pr-gate-check-throwaway
Open

Neutralize spreadsheet formula characters in CSV export#916
carfeii wants to merge 1 commit into
sharkdp:masterfrom
carfeii:pr-gate-check-throwaway

Conversation

@carfeii

@carfeii carfeii commented Aug 5, 2026

Copy link
Copy Markdown

Fixes #915.

Summary

CsvExporter::serialize (src/export/csv.rs) writes the benchmarked
command name and every --parameter-list/--parameter-scan value
directly into CSV cells with no protection against spreadsheet formula
interpretation. Excel, LibreOffice Calc, and Google Sheets all treat a
cell beginning with =, +, -, or @ as a formula to evaluate on
open, independent of the file's .csv extension. Since both the command
string and any parameter value can be attacker-influenced (for example, a
benchmark parameterized over externally-submitted names in a CI job), an
exported CSV given to someone else to review could execute an
attacker-chosen formula the moment they open it. This is CWE-1236.

Fix

Adds neutralize_formula, which prefixes a value with a single quote if
it begins with a formula-triggering character (=, +, -, @, tab, or
carriage return), so spreadsheet applications display it as literal text
instead of evaluating it. Applied to both the command field and every
parameter value in CsvExporter::serialize. This is the standard
mitigation for CWE-1236.

Testing

  • cargo test --release passes in full across all suites (unit,
    common, execution_order_tests, integration_tests).
  • Added test_csv_formula_injection_is_neutralized, asserting a command
    starting with = and a parameter value starting with @ are both
    prefixed with a single quote in the exported CSV.
  • Manually reproduced the injection against an unpatched build: ran
    hyperfine --parameter-list payload '=1+1' --export-csv out.csv -- 'echo hi {payload}', confirmed the raw file contained the literal,
    unescaped text =1+1, then converted it with LibreOffice Calc headless
    (soffice --headless --calc --convert-to ods, then back to CSV) and
    confirmed the cell evaluated to 2. Repeated the same steps against
    this branch: the raw file now contains '=1+1, and the value survives
    the LibreOffice round-trip unchanged (still '=1+1), confirming it is
    displayed as text rather than evaluated.

CsvExporter::serialize wrote the benchmarked command name and every
--parameter-list/--parameter-scan value directly into CSV cells with no
protection against spreadsheet formula interpretation. Excel, LibreOffice
Calc, and Google Sheets all treat a cell beginning with =, +, -, or @ as
a formula to evaluate on open, independent of the file's .csv extension.
Since both the command string and any parameter value can be
attacker-influenced (for example, a benchmark parameterized over
externally-submitted names), an exported CSV given to someone else to
review could execute an attacker-chosen formula the moment they open it.

Add neutralize_formula, which prefixes a value with a single quote if it
begins with a formula-triggering character (=, +, -, @, tab, or carriage
return), and use it for both the command field and every parameter value.
This is the standard mitigation for CWE-1236.

See sharkdp#915.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CSV export writes command and parameter values unescaped, allowing spreadsheet formula injection when the exported file is opened

1 participant