@@ -884,6 +884,14 @@ function getCategoryEmoji(category, type) {
884884 return type === "income" ? CATEGORY_EMOJIS [ "income_default" ] : CATEGORY_EMOJIS [ "expense_default" ] ;
885885}
886886
887+ // Escapes a user-controlled string so it renders as literal text when
888+ // interpolated into an innerHTML template, preventing HTML/script injection.
889+ function escapeHTML ( str ) {
890+ const div = document . createElement ( "div" ) ;
891+ div . textContent = str ;
892+ return div . innerHTML ;
893+ }
894+
887895function initBudgetTracker ( ) {
888896 let transactions = [ ] ;
889897 let activeBreakdownType = "expense" ;
@@ -1181,7 +1189,7 @@ function initBudgetTracker() {
11811189 item . className = "breakdown-item" ;
11821190 item . innerHTML = `
11831191 <div class="breakdown-info">
1184- <span class="breakdown-name">${ emoji } ${ cat } (${ percent . toFixed ( 1 ) } %)</span>
1192+ <span class="breakdown-name">${ emoji } ${ escapeHTML ( cat ) } (${ percent . toFixed ( 1 ) } %)</span>
11851193 <span class="breakdown-amount">₹${ amount . toLocaleString ( 'en-IN' , { minimumFractionDigits : 2 , maximumFractionDigits : 2 } ) } </span>
11861194 </div>
11871195 <div class="breakdown-bar-bg">
@@ -1230,8 +1238,8 @@ function initBudgetTracker() {
12301238 <span>${ emoji } </span>
12311239 </div>
12321240 <div class="trans-text">
1233- <span class="trans-category-tag">${ t . category } </span>
1234- ${ t . description ? `<span class="trans-desc">${ t . description } </span>` : '' }
1241+ <span class="trans-category-tag">${ escapeHTML ( t . category ) } </span>
1242+ ${ t . description ? `<span class="trans-desc">${ escapeHTML ( t . description ) } </span>` : '' }
12351243 <span class="trans-date">${ t . date } </span>
12361244 </div>
12371245 </div>
0 commit comments