fix(admin-redesign): security — stored XSS via user name in onclick
Security review caught: per-row hover actions (users.js) and async user picker (shop.js, gam.js) interpolated user-controlled name into JS string literals inside onclick. LS.esc() escapes & < > " but NOT backslash; the .replace(/'/g, '\'') fallback was broken. Attack: any authenticated user could set their name to a\'); alert(1); // via PATCH /api/auth/profile (stripTags doesn't strip \) — admin viewing the users/shop/gam picker would execute arbitrary JS. Fix: switch from JS-string interpolation to data-uid/data-name attributes, read via dataset in handler. esc() correctly escapes for HTML-attribute context; dataset returns the raw string with zero parse re-entry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -118,17 +118,19 @@
|
||||
_gamSearchTimer = setTimeout(async () => {
|
||||
try {
|
||||
const r = await LS.adminGetUsers({ q, limit: 8 });
|
||||
box.innerHTML = (r.users || []).map(u => `<div class="us-item" onclick="gamPickUser(${u.id}, '${esc(u.name || u.email)}', '${prefix}')">
|
||||
<span>${esc(u.name || u.email)}</span><span class="us-role">${u.role}</span>
|
||||
const label = u => u.name || u.email;
|
||||
box.innerHTML = (r.users || []).map(u => `<div class="us-item" data-uid="${u.id}" data-name="${esc(label(u))}" data-prefix="${esc(prefix)}" onclick="gamPickUser(this)">
|
||||
<span>${esc(label(u))}</span><span class="us-role">${esc(u.role)}</span>
|
||||
</div>`).join('') || '<div class="us-item" style="color:var(--text-3)">Не найдено</div>';
|
||||
box.classList.add('open');
|
||||
} catch(e) { box.classList.remove('open'); }
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function gamPickUser(id, name, prefix) {
|
||||
document.getElementById(prefix + '-uid').value = id;
|
||||
document.getElementById(prefix + '-user').value = name;
|
||||
function gamPickUser(el) {
|
||||
const prefix = el.dataset.prefix;
|
||||
document.getElementById(prefix + '-uid').value = el.dataset.uid;
|
||||
document.getElementById(prefix + '-user').value = el.dataset.name || '';
|
||||
document.getElementById(prefix + '-results').classList.remove('open');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user