From 2b6937ee43d3a22a5c67e6fbbde2093d40264248 Mon Sep 17 00:00:00 2001 From: Akshara Date: Sun, 12 Jul 2026 12:03:38 +0000 Subject: [PATCH] fix: escape user-controlled category/description before innerHTML injection (#1583) --- web-app/js/projects/budget-tracker.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/web-app/js/projects/budget-tracker.js b/web-app/js/projects/budget-tracker.js index 18954d32..66022fdd 100644 --- a/web-app/js/projects/budget-tracker.js +++ b/web-app/js/projects/budget-tracker.js @@ -884,6 +884,14 @@ function getCategoryEmoji(category, type) { return type === "income" ? CATEGORY_EMOJIS["income_default"] : CATEGORY_EMOJIS["expense_default"]; } +// Escapes a user-controlled string so it renders as literal text when +// interpolated into an innerHTML template, preventing HTML/script injection. +function escapeHTML(str) { + const div = document.createElement("div"); + div.textContent = str; + return div.innerHTML; +} + function initBudgetTracker() { let transactions = []; let activeBreakdownType = "expense"; @@ -1181,7 +1189,7 @@ function initBudgetTracker() { item.className = "breakdown-item"; item.innerHTML = `
- ${emoji} ${cat} (${percent.toFixed(1)}%) + ${emoji} ${escapeHTML(cat)} (${percent.toFixed(1)}%) ₹${amount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
@@ -1230,8 +1238,8 @@ function initBudgetTracker() { ${emoji}
- ${t.category} - ${t.description ? `${t.description}` : ''} + ${escapeHTML(t.category)} + ${t.description ? `${escapeHTML(t.description)}` : ''} ${t.date}