Skip to content

fix(security): neutralize CSV formula injection in logs export#4952

Merged
waleedlatif1 merged 3 commits into
stagingfrom
fix/csv
Jun 10, 2026
Merged

fix(security): neutralize CSV formula injection in logs export#4952
waleedlatif1 merged 3 commits into
stagingfrom
fix/csv

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Neutralize spreadsheet formula triggers (=, +, -, @, tab, CR) in GET /api/logs/export CSV output by prefixing affected cells with a single quote
  • Closes a stored, cross-user CSV/formula injection vector via workflow names and execution output (RFC-4180 quoting alone doesn't stop Excel/Sheets from evaluating formulas)
  • Mirrors the existing neutralizeCsvFormula() already used in the table export route

Type of Change

  • Bug fix

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Jun 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 10, 2026 8:49pm

Request Review

@cursor

cursor Bot commented Jun 10, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Small, defensive output sanitization on CSV exports with no auth or data-model changes; table export behavior is preserved via the same helper.

Overview
Centralizes CSV formula-injection protection by moving neutralizeCsvFormula into @/lib/core/utils/csv and reusing it from both export paths.

Logs export (GET /api/logs/export) now runs string cell values through neutralizeCsvFormula inside escapeCsv before RFC-4180 quoting, so fields like workflow names, messages, and trace JSON cannot open as formulas when the CSV is opened in Excel/Sheets.

Table export drops its inline copy of the same helper and imports the shared module; CSV cell behavior is unchanged.

Reviewed by Cursor Bugbot for commit 8e8bb12. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR closes a stored CSV formula-injection vector in GET /api/logs/export by applying the existing neutralizeCsvFormula helper to all string cell values, and consolidates the previously duplicated helper into a single shared module at lib/core/utils/csv.ts.

  • New shared utility (lib/core/utils/csv.ts): neutralizeCsvFormula is extracted from the table export route and exported for reuse, making the trigger-character set a single source of truth.
  • Logs export fix (app/api/logs/export/route.ts): escapeCsv now branches on typeof value === 'string' — strings are formula-neutralized before RFC-4180 quoting; non-string types (numbers, booleans) go through String() unchanged, which is safe because spreadsheets parse them as numeric values.
  • Table export cleanup (app/api/table/[tableId]/export/route.ts): Local definition removed; now imports from the shared utility with no behavioural change.

Confidence Score: 5/5

Safe to merge — the change is a targeted security hardening with no behavioural regressions; the only modified logic is the string branch of escapeCsv in the logs export route, and the table export route is a pure refactor with identical runtime behaviour.

All three files have narrow, well-scoped changes: a new four-line utility, one extra import plus one-line branch in the logs export, and a dead-code removal in the table export. The neutralization is applied at the correct point in the pipeline (before RFC-4180 quoting), non-string values are correctly left on the numeric path, and the shared function is identical to the original inline version it replaces.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/lib/core/utils/csv.ts New shared utility exporting neutralizeCsvFormula; regex covers all known formula-injection triggers (=, +, -, @, tab, CR). Correctly returns the original value unchanged if no trigger is present.
apps/sim/app/api/logs/export/route.ts Imports neutralizeCsvFormula from the shared utility and applies it inside escapeCsv for string values only, leaving numbers/booleans on the String() path (which is safe as spreadsheets parse them as numbers, not formulas). Correct ordering: neutralize then RFC-4180 quote.
apps/sim/app/api/table/[tableId]/export/route.ts Local neutralizeCsvFormula definition removed; now imports from the shared utility. Behaviour is identical to before — no functional changes beyond the refactor.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Cell value] --> B{typeof value}
    B -- string --> C[neutralizeCsvFormula]
    B -- number or boolean --> D[String coercion]
    C --> E{Starts with trigger char?}
    E -- yes --> F[Prefix with single-quote]
    E -- no --> G[Unchanged]
    F --> H[RFC-4180 CSV quoting]
    G --> H
    D --> H
    H --> I{Contains special chars?}
    I -- yes --> J[Wrap in double-quotes and escape]
    I -- no --> K[Emit verbatim]
    J --> L[CSV field output]
    K --> L
Loading

Reviews (3): Last reviewed commit: "fix(csv): only neutralize string cells i..." | Re-trigger Greptile

Comment thread apps/sim/app/api/logs/export/route.ts Outdated
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/app/api/logs/export/route.ts Outdated
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 8e8bb12. Configure here.

@waleedlatif1 waleedlatif1 merged commit dd3705e into staging Jun 10, 2026
14 checks passed
@waleedlatif1 waleedlatif1 deleted the fix/csv branch June 10, 2026 21:01
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.

1 participant