security: escape dynamic content in innerHTML to prevent XSS
This commit addresses several XSS vulnerabilities by ensuring that dynamic data from external APIs (GitHub) and error messages are properly escaped before being rendered via innerHTML. Affected areas: - openVersionMenu error handling and version list - showErrorModal title and button text - showToast message content All changes were verified with a reproduction test case. Co-authored-by: TauNeutrino <1600410+TauNeutrino@users.noreply.github.com>
This commit is contained in:
@@ -899,7 +899,7 @@ export async function loadMenuDataFromAPI() {
|
||||
import('./ui_helpers.js').then(uiHelpers => {
|
||||
uiHelpers.showErrorModal(
|
||||
'Keine Verbindung',
|
||||
`Die Menüdaten konnten nicht geladen werden. Möglicherweise besteht keine Verbindung zur API oder zur Bessa-Webseite.<br><br><small style="color:var(--text-secondary)">${error.message}</small>`,
|
||||
`Die Menüdaten konnten nicht geladen werden. Möglicherweise besteht keine Verbindung zur API oder zur Bessa-Webseite.<br><br><small style="color:var(--text-secondary)">${escapeHtml(error.message)}</small>`,
|
||||
'Zur Original-Seite',
|
||||
'https://web.bessa.app/knapp-kantine'
|
||||
);
|
||||
@@ -947,7 +947,7 @@ export function showToast(message, type = 'info') {
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
const icon = type === 'success' ? 'check_circle' : type === 'error' ? 'error' : 'info';
|
||||
toast.innerHTML = `<span class="material-icons-round">${icon}</span><span>${message}</span>`;
|
||||
toast.innerHTML = `<span class="material-icons-round">${icon}</span><span>${escapeHtml(message)}</span>`;
|
||||
container.appendChild(toast);
|
||||
requestAnimationFrame(() => toast.classList.add('show'));
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -516,12 +516,12 @@ export function openVersionMenu() {
|
||||
|
||||
let action = '';
|
||||
if (!isCurrent) {
|
||||
action = `<a href="${v.url}" target="_blank" class="install-link" title="${v.tag} installieren">Installieren</a>`;
|
||||
action = `<a href="${escapeHtml(v.url)}" target="_blank" class="install-link" title="${escapeHtml(v.tag)} installieren">Installieren</a>`;
|
||||
}
|
||||
|
||||
li.innerHTML = `
|
||||
<div class="version-info">
|
||||
<strong>${v.tag}</strong>
|
||||
<strong>${escapeHtml(v.tag)}</strong>
|
||||
${badge}
|
||||
</div>
|
||||
${action}
|
||||
@@ -554,7 +554,7 @@ export function openVersionMenu() {
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
container.innerHTML = `<p style="color:#e94560;">Fehler: ${e.message}</p>`;
|
||||
container.innerHTML = `<p style="color:#e94560;">Fehler: ${escapeHtml(e.message)}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,7 +661,7 @@ export function showErrorModal(title, htmlContent, btnText, url) {
|
||||
<div class="modal-header">
|
||||
<h2 style="color: var(--error-color); display: flex; align-items: center; gap: 10px;">
|
||||
<span class="material-icons-round">signal_wifi_off</span>
|
||||
${title}
|
||||
${escapeHtml(title)}
|
||||
</h2>
|
||||
</div>
|
||||
<div style="padding: 20px;">
|
||||
@@ -682,7 +682,7 @@ export function showErrorModal(title, htmlContent, btnText, url) {
|
||||
justify-content: center;
|
||||
transition: transform 0.1s;
|
||||
">
|
||||
${btnText}
|
||||
${escapeHtml(btnText)}
|
||||
<span class="material-icons-round">open_in_new</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user