fix: escape user-controlled fields in admin/users innerHTML to prevent stored XSS
u.name and u.email are stored user input and were interpolated raw into tbody.innerHTML. Added esc() helper and applied to name, email, and role display string. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -240,6 +240,10 @@
|
|||||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||||
let usersData = [];
|
let usersData = [];
|
||||||
|
|
||||||
|
function esc(s) {
|
||||||
|
return String(s).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', loadUsers);
|
document.addEventListener('DOMContentLoaded', loadUsers);
|
||||||
|
|
||||||
async function loadUsers() {
|
async function loadUsers() {
|
||||||
@@ -285,11 +289,11 @@
|
|||||||
tbody.innerHTML = usersData.length ? usersData.map((u, i) => `
|
tbody.innerHTML = usersData.length ? usersData.map((u, i) => `
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-xs font-bold opacity-30">${i + 1}</td>
|
<td class="text-xs font-bold opacity-30">${i + 1}</td>
|
||||||
<td><div class="font-bold">${u.name}</div></td>
|
<td><div class="font-bold">${esc(u.name)}</div></td>
|
||||||
<td class="text-sm opacity-70">${u.email}</td>
|
<td class="text-sm opacity-70">${esc(u.email)}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="badge badge-sm ${roleBadge[u.role] || 'badge-neutral'} badge-outline capitalize">
|
<span class="badge badge-sm ${roleBadge[u.role] || 'badge-neutral'} badge-outline capitalize">
|
||||||
${roleLabels[u.role] || u.role}
|
${esc(roleLabels[u.role] || u.role)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
|
|||||||
Reference in New Issue
Block a user