Skip to content
FeaturesPricingAffiliateBlogHelpAboutContact
Get StartedSign In
Back to Blog
industry2026-05-2412 min read

My accountant found a formula injection in my tax report CSV — TaxReport csvField sweep (PR #598 AAA F5)

Camille Marseille Le Panier Rue Caisserie 43-yo 11-yr Bouillabaisse Vieux-Port 55-cover Provencal seafood + traditional bouillabaisse + soupe de poisson + aioli platter thMenu Pro tier 19 months. Quarterly downloads tax-report CSV thMenu admin dashboard sends to CPA Marc seasonal Provencal restaurant scene office La Joliette. Tuesday morning Q1 2026 tax CSV email. 3 hours later Marc pointed reply Camille row 47 product_name =cmd|/c calc!A0 Numbers warning popup security bug. Camille froze didn't open CSV own laptop after calc warning. Admin panel item 47 Bouillabaisse Marseillaise Tradition product_name normal but CSV =cmd|/c calc!A0. 3 weeks ago hired Antoine new front-of-house staff menu-edit perms holiday Cassis. Antoine no I didn't touch menu side. Support emailed Camille formula injection vector. Engineering 3 wrong theories (1) Antoine XSS payload click audit log staff_audit_logs antoine_id action product 0 product edits never touched menu; (2) attacker outside API bypass auth WAF log 90 days 403 = 41 legitimate bot no bypassed malicious POSTs; (3) Camille copy-paste possible but admin panel displayed normally stored value clean formula CSV export only. Correct theory TaxReport CSV export not using csvField helper. Forensic apps/web-admin/src/app/api/tax-report/route.ts rows.push([orderDate productName quantity unitPrice taxRate taxAmount].join(',)) no escaping RFC 4180 §2.6 violated + no formula-prefix sanitization. apps/web-admin/src/lib/csv.ts csvField helper existed PR #365 audit-finding YY used by 8 other CSV exports (orders+customers+products+feedback+reservations+affiliate-stats+cron-status+soc2-evidence) tax report added later missed sweep. csvField two layers (1) RFC 4180 quoting value contains , or or \n wrap in ... escape internal as ; (2) formula-prefix neutralization first char =/+/-/@/\t/\r prepend single quote prevents Excel/LibreOffice/Numbers formula interpretation doesn't change readable text. OWASP CSV Injection Cheat Sheet recommended since 2017 Excel CSV import =cmd|/c calc!A0 + DDE older versions trigger calc.exe/PowerShell modern Excel partially blocks dangerous corporate Office old versions. Source how =cmd ended row 47 query SELECT product_name FROM products WHERE id Bouillabaisse Marseillaise =cmd|/c calc!A0 Tradition mid-value embedded admin panel HTML-escaped renders plain text CSV separates commas without quoting parses as either two fields or formula-prefixed depending on reader. updated_at 2 months ago updated_by script:menu-backfill-v2 batch CSV import migrate old menu Excel workbook Camille Q4 2025. Excel cell formula value tested Camille or prior employee import script read Excel cell display value wrote product_name formula string raw text stored as-is admin panel HTML-escapes CSV export wasn't applying field-level escape. Injection point 2-month-old migrate-from-excel script behaves like stored XSS but lives CSV side detonates accountant's machine Camille not attacker victim script-of-opportunity. PR #598 batch AAA F5 2-layer fix Layer 1 TaxReport CSV export csvField helper rows.push([...].map(csvField).join(,)) every field RFC 4180 quoted + formula-prefix neutralized =cmd|/c calc!A0 → '=cmd|/c calc!A0 Excel doesn't interpret formula. Layer 2 menu-backfill-v2 script sanitization Excel→D1 import script product_name + description + ingredients formula-prefix detector =/+/-/@/\t/\r prepend stripped + warn log stored data clean. Production audit all products tables formula-prefix scan 23 products 7 restaurants historical Excel imports UPDATE products SET REPLACE + audit log notice email operators formula strings historical Excel imports sanitized no action required. YY sweep PR #365 csvField helper start 8 web-admin CSV exports AAA F5 last (tax-report) shipped sweep code-base-complete CI grep guard new PR .join(,) + string array pattern do you need csvField warning PR template checkbox CSV csvField? Camille email + Marc thank-you note + 1-month Pro credit Marc blog 2.4k engagement independent CPAs south France. Hasan Ordu Altinordu Karadeniz Hamsi + Mihlama Sofrasi 45-cover Black Sea cuisine 13-yr accountant Selvi found same vector item 62 product_name formula prefix 2-month-old menu-backfill-v2 import same fix 1-month Pro credit + Hall of Fame Selvi. Pattern every endpoint exports user-input data CSV must route csvField helper + every Excel/CSV import script formula-prefix sanitization RFC 4180 §2.6 + OWASP CSV Injection canonical. Sibling sweep monorepo 8 web-admin CSV exports YY sweep PR #365 AAA F5 8/8 complete new exports super-admin export-affiliate-payouts + admin export-staff-shifts ship helper default. Implementation csvField shared lib + RFC 4180 quoting + formula-prefix 6 dangerous chars + route all CSV exports + Excel/CSV import scripts sanitize user-input + production audit existing data scan + CI grep guard + PR template checkbox. PR #598 reference.

th

thMenu Team

thmenu.com

Found this helpful? Share it.