From fde7515783bfd3614c5de22902ee7c33b86ad53f Mon Sep 17 00:00:00 2001 From: Akshita-2307 Date: Sat, 30 May 2026 17:30:20 +0530 Subject: [PATCH] fix: resolve multiple DOM-based XSS and Electron security vulnerabilities - escapeAttr: escape &, <, > characters to prevent HTML/attribute injection - setWindowOpenHandler: deny non-http URLs (file://, data:) to stop local file disclosure - window.open: add noopener,noreferrer to prevent reverse tabnapping - onclick handlers: sanitize script paths and category names to prevent stored XSS --- main.js | 6 ++++-- ui/app.js | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/main.js b/main.js index 8be8516..197338c 100644 --- a/main.js +++ b/main.js @@ -162,10 +162,12 @@ function createWindow(port) { }); mainWindow.webContents.setWindowOpenHandler(({ url }) => { - if (url.startsWith(baseUrl) || !url.startsWith('http')) { + if (url.startsWith(baseUrl)) { return { action: 'allow' }; } - require('electron').shell.openExternal(url); + if (url.startsWith('http')) { + require('electron').shell.openExternal(url); + } return { action: 'deny' }; }); diff --git a/ui/app.js b/ui/app.js index c4fb694..71bfc03 100644 --- a/ui/app.js +++ b/ui/app.js @@ -1826,7 +1826,7 @@ async function executePR(relPath, branch, message, repoUrl) { `Successfully pushed to branch '${data.branch}'.\n\nWould you like to open the Pull Request page on GitHub?` ) ) { - window.open(data.pr_url, '_blank'); + window.open(data.pr_url, '_blank', 'noopener,noreferrer'); } } else { if (typeof DebuggerConsole !== 'undefined') { @@ -2821,9 +2821,10 @@ function renderSidebar() { totalScripts += filteredScripts.length; const isExpanded = state.expandedCategories.has(cat) || !!query; + const escapedCat = escapeAttr(cat); html += `
-
+
@@ -2835,17 +2836,18 @@ function renderSidebar() { ${filteredScripts.map(s => { let lockIcon = s.locked ? `${ICONS.lock}` : ''; const displayName = ((s.name || '') + '').trim() || s.file || (s.relative_path || '').split('/').pop() || ''; + const escapedPath = escapeAttr(s.relative_path); return `
  • ${lockIcon} ${ICONS.script} ${escapeHtml(displayName)} + onclick="event.stopPropagation(); toggleFavorite('${escapedPath}')"> ${ICONS.favorite}
  • @@ -2884,10 +2886,11 @@ function renderSidebar() { favsSection.style.display = ''; favsList.innerHTML = favScripts.map(s => { const displayName = ((s.name || '') + '').trim() || s.file || (s.relative_path || '').split('/').pop() || ''; + const escapedPath = escapeAttr(s.relative_path); return `
  • + onclick="selectScript('${escapedPath}')" + onkeydown="handleKeyboardAction(event, () => selectScript('${escapedPath}'))"> ${ICONS.favorite} ${escapeHtml(displayName)}
  • @@ -3712,7 +3715,7 @@ function escapeHtml(text) { } function escapeAttr(text) { - return text.replace(/"/g, '"').replace(/'/g, '''); + return String(text).replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(//g, '>'); } function removeNotification(notification) {