From b8bfa2941cc350cb86c9a4a3fa5a333d571a03d6 Mon Sep 17 00:00:00 2001 From: bigjakk Date: Sun, 1 Mar 2026 09:04:50 -0800 Subject: [PATCH] =?UTF-8?q?v0.5.1=20=E2=80=94=20Escape=20userscript=20meta?= =?UTF-8?q?data=20in=20settings=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes XSS via malicious userscript @name, @author, @version, @description metadata and script setting titles/descriptions. Also escapes checkbox grid labels. All use existing escapeHtml() helper. Co-Authored-By: Claude Opus 4.6 --- package.json | 2 +- src/preload/index.ts | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index fce86c7..39d0ff8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "krunker-civilian-client", - "version": "0.5.0", + "version": "0.5.1", "description": "Cross-platform Krunker game client", "main": "dist/main/index.js", "homepage": "https://gitea.crjlab.net/bigjakk/krunker-civilian-client", diff --git a/src/preload/index.ts b/src/preload/index.ts index 9b4487c..6e3adc6 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -372,7 +372,7 @@ function createCheckboxGrid(opts: { const label = document.createElement('label'); label.className = 'hostOpt'; label.innerHTML = - '' + item.label + '' + + '' + escapeHtml(item.label) + '' + '' + '
'; const cb = label.querySelector('input') as HTMLInputElement; @@ -1114,12 +1114,12 @@ function renderUserscriptsSection(body: HTMLElement): void { const scriptRow = document.createElement('div'); scriptRow.className = 'setting settName safety-0 bool'; - const displayName = inst.meta.name || inst.filename; + const displayName = escapeHtml(inst.meta.name || inst.filename); let metaParts: string[] = []; - if (inst.meta.author) metaParts.push('by ' + inst.meta.author); - if (inst.meta.version) metaParts.push('v' + inst.meta.version); + if (inst.meta.author) metaParts.push('by ' + escapeHtml(inst.meta.author)); + if (inst.meta.version) metaParts.push('v' + escapeHtml(inst.meta.version)); const metaLine = metaParts.length > 0 ? '' + metaParts.join(' · ') + '' : ''; - const descText = inst.meta.desc || ''; + const descText = escapeHtml(inst.meta.desc || ''); scriptRow.innerHTML = '' + displayName + '' + @@ -1161,8 +1161,8 @@ function renderScriptSettings(inst: UserscriptInstance, container: HTMLElement): const row = document.createElement('div'); row.className = 'setting settName safety-0' + (typeClass ? ' ' + typeClass : ''); row.innerHTML = - '' + setting.title + '' + - (setting.desc ? '
' + setting.desc + '
' : ''); + '' + escapeHtml(setting.title) + '' + + (setting.desc ? '
' + escapeHtml(setting.desc) + '
' : ''); switch (setting.type) { case 'bool': {