From 6ec2780b116c5181ab68d92db727af82961d3b98 Mon Sep 17 00:00:00 2001 From: Vedhant26 Date: Sat, 30 May 2026 22:49:55 +0530 Subject: [PATCH] fix(security): prevent CSV format corruption and formula injection in export --- backend/controllers/csvDownload.controller.js | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/backend/controllers/csvDownload.controller.js b/backend/controllers/csvDownload.controller.js index 45dc6f1..a1836cf 100644 --- a/backend/controllers/csvDownload.controller.js +++ b/backend/controllers/csvDownload.controller.js @@ -36,6 +36,14 @@ function formatIcsDate(dateInput) { return `${year}${month}${day}T${hours}${minutes}${seconds}Z`; } +function escapeCsvField(value) { + let str = String(value || ''); + if (/^[=+\-@]/.test(str)) { + str = "'" + str; // Prevent formula injection + } + return `"${str.replace(/"/g, '""')}"`; +} + function buildCalendarIcs(tasks = []) { const dtstamp = formatIcsDate(new Date().toISOString()); const events = tasks @@ -81,14 +89,14 @@ async function downloadData(req, res) { const rows = [ ['Task ID', 'Subject', 'Title', 'Due At', 'Status', 'Priority', 'Confidence Score', 'Notes'], ...data.map(task => [ - task.id, - task.subject_name, - task.title, - task.due_at, - task.status, - task.priority, - task.confidence_score, - `"${(task.notes || '').replace(/"/g, '""')}"`, + escapeCsvField(task.id), + escapeCsvField(task.subject_name), + escapeCsvField(task.title), + escapeCsvField(task.due_at), + escapeCsvField(task.status), + escapeCsvField(task.priority), + escapeCsvField(task.confidence_score), + escapeCsvField(task.notes), ]), ]; @@ -123,4 +131,5 @@ module.exports = { buildCalendarIcs, formatIcsDate, escapeIcsText, + escapeCsvField, };