Neutralize CSV formula injection in trader history exports (#432) #960

Merged
PlasticDigits merged 1 commit from fix/432-csv-formula-injection into main 2026-06-29 15:49:34 +00:00
PlasticDigits commented 2026-06-29 15:41:56 +00:00 (Migrated from gitlab.com)

Summary

Addresses SEC-F12 (#432): trader history CSV exports (text_csv.rs) now neutralize spreadsheet formula prefixes before RFC 4180 quoting.

  • csv_escape_cell prefixes cells starting with =, +, -, or @ with a leading ' so Excel/LibreOffice/Google Sheets do not interpret them as formulas.
  • Unit tests cover bare prefixes, quoted cells with embedded quotes/commas, and a TradeResponse row with offer_asset = "=HYPERLINK(...)".
  • Invariants documented in docs/indexer-invariants.md and skills/AGENTS_FRONTEND_ORDER_HISTORY.md.

Acceptance checklist

Criterion Verification Result
Test asserts formula-injection safety for leading =, +, -, @ cd indexer && cargo test --lib api::text_csv::tests::csv_escape_cell_neutralizes_formula_prefixes -- --nocapture PASS
Test visible in source (text_csv.rs) grep -n 'csv_escape_cell_neutralizes' indexer/src/api/text_csv.rs PASS
End-to-end CSV export still works cd indexer && cargo test --test api_traders get_trader_trades_csv_returns_text_csv -- --test-threads=1 PASS
Invariants documented docs/indexer-invariants.md trader history row + skills/AGENTS_FRONTEND_ORDER_HISTORY.md PASS

Third-party verification

# Unit tests (no Postgres required)
cd indexer && cargo test --lib api::text_csv -- --nocapture

# Integration CSV smoke (requires Postgres; make setup-indexer-postgres)
cd indexer && cargo test --test api_traders get_trader_trades_csv_returns_text_csv -- --test-threads=1

Confirm indexer/src/api/text_csv.rs contains:

  • csv_escape_cell_neutralizes_bare_formula_prefix
  • csv_escape_cell_neutralizes_formula_prefixes (loops =, +, -, @)
  • trader_swaps_csv_neutralizes_formula_in_offer_asset
## Summary Addresses SEC-F12 ([#432](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/432)): trader history CSV exports (`text_csv.rs`) now neutralize spreadsheet formula prefixes before RFC 4180 quoting. - `csv_escape_cell` prefixes cells starting with `=`, `+`, `-`, or `@` with a leading `'` so Excel/LibreOffice/Google Sheets do not interpret them as formulas. - Unit tests cover bare prefixes, quoted cells with embedded quotes/commas, and a `TradeResponse` row with `offer_asset = "=HYPERLINK(...)"`. - Invariants documented in `docs/indexer-invariants.md` and `skills/AGENTS_FRONTEND_ORDER_HISTORY.md`. ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Test asserts formula-injection safety for leading `=`, `+`, `-`, `@` | `cd indexer && cargo test --lib api::text_csv::tests::csv_escape_cell_neutralizes_formula_prefixes -- --nocapture` | PASS | | Test visible in source (`text_csv.rs`) | `grep -n 'csv_escape_cell_neutralizes' indexer/src/api/text_csv.rs` | PASS | | End-to-end CSV export still works | `cd indexer && cargo test --test api_traders get_trader_trades_csv_returns_text_csv -- --test-threads=1` | PASS | | Invariants documented | `docs/indexer-invariants.md` trader history row + `skills/AGENTS_FRONTEND_ORDER_HISTORY.md` | PASS | ## Third-party verification ```bash # Unit tests (no Postgres required) cd indexer && cargo test --lib api::text_csv -- --nocapture # Integration CSV smoke (requires Postgres; make setup-indexer-postgres) cd indexer && cargo test --test api_traders get_trader_trades_csv_returns_text_csv -- --test-threads=1 ``` Confirm `indexer/src/api/text_csv.rs` contains: - `csv_escape_cell_neutralizes_bare_formula_prefix` - `csv_escape_cell_neutralizes_formula_prefixes` (loops `=`, `+`, `-`, `@`) - `trader_swaps_csv_neutralizes_formula_in_offer_asset`
PlasticDigits commented 2026-06-29 15:46:35 +00:00 (Migrated from gitlab.com)

Security review — MR !960

Commit reviewed: c14c989fa192542e89ed25cbd7f24c07c04ed70a
Scope: indexer/src/api/text_csv.rs (csv_escape_cell formula-prefix neutralization + unit tests), docs/indexer-invariants.md, skills/AGENTS_FRONTEND_ORDER_HISTORY.md
Outcome: FINDINGS: 0 medium+

Summary

Reviewed the SEC-F12 / #432 fix that prefixes CSV cells starting with =, +, -, or @ with a leading ' before RFC 4180 quoting. Traced attacker-controlled inputs (CW20 symbol via trade_response_from_swap_row → offer_asset/ask_asset; maker/owner/sender/tx_hash from indexed chain events) through join_row → csv_escape_cell → trader_*_csv → unauthenticated GET /api/v1/traders/{addr}/...?format=csv responses.

The change correctly neutralizes the documented formula-prefix vector for all exported string cells. Existing controls (read-only public API, parameterized SQL, trader_csv_slug filename sanitization, format allowlist) remain intact; no new injection, authz, SSRF, XSS, or secret-leak surfaces were introduced.

Checks performed

  • Verified csv_escape_cell applies the ' prefix before quote detection so comma-containing formula payloads are still neutralized inside quoted fields.
  • Confirmed all three trader-history CSV builders route every cell through csv_escape_cell.
  • Ran cargo test --lib api::text_csv::tests — all 4 tests pass.
  • Considered tab/whitespace-prefixed formula bypasses (CWE-1236); these are outside the accepted #432 checklist (=, +, -, @ only) and require non-standard CW20 metadata; not rated medium+ for this diff.

Security review: no medium+ findings on this diff. No inline threads.

## Security review — MR !960 **Commit reviewed:** `c14c989fa192542e89ed25cbd7f24c07c04ed70a` **Scope:** `indexer/src/api/text_csv.rs` (`csv_escape_cell` formula-prefix neutralization + unit tests), `docs/indexer-invariants.md`, `skills/AGENTS_FRONTEND_ORDER_HISTORY.md` **Outcome:** **FINDINGS: 0** medium+ ### Summary Reviewed the SEC-F12 / #432 fix that prefixes CSV cells starting with `=`, `+`, `-`, or `@` with a leading `'` before RFC 4180 quoting. Traced attacker-controlled inputs (CW20 `symbol` via `trade_response_from_swap_row` → `offer_asset`/`ask_asset`; `maker`/`owner`/`sender`/`tx_hash` from indexed chain events) through `join_row` → `csv_escape_cell` → `trader_*_csv` → unauthenticated `GET /api/v1/traders/{addr}/...?format=csv` responses. The change correctly neutralizes the documented formula-prefix vector for all exported string cells. Existing controls (read-only public API, parameterized SQL, `trader_csv_slug` filename sanitization, `format` allowlist) remain intact; no new injection, authz, SSRF, XSS, or secret-leak surfaces were introduced. ### Checks performed - Verified `csv_escape_cell` applies the `'` prefix before quote detection so comma-containing formula payloads are still neutralized inside quoted fields. - Confirmed all three trader-history CSV builders route every cell through `csv_escape_cell`. - Ran `cargo test --lib api::text_csv::tests` — all 4 tests pass. - Considered tab/whitespace-prefixed formula bypasses (CWE-1236); these are outside the accepted #432 checklist (`=`, `+`, `-`, `@` only) and require non-standard CW20 metadata; not rated medium+ for this diff. **Security review: no medium+ findings on this diff.** No inline threads.
PlasticDigits (Migrated from gitlab.com) merged commit 6afbcb194f into main 2026-06-29 15:49:34 +00:00
PlasticDigits commented 2026-06-29 15:49:35 +00:00 (Migrated from gitlab.com)

mentioned in commit 6afbcb194f

mentioned in commit 6afbcb194f92e57a5a96c37464ae40adf43f003f
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic!960
No description provided.