Harden security: CORS, XSS, rate limiting, CSP, SRI
- Lock down CORS to ALLOWED_ORIGINS env var (was wildcard) - Fix admin panel XSS: use data-username attributes instead of interpolating usernames into onclick handlers - Add rate limiting to /api/auth/register (3r/m) and /api/admin/* (10r/m); set limit_req_status 429 - Add Content-Security-Policy header restricting scripts to self and cdn.jsdelivr.net - Add Subresource Integrity hash to Chart.js CDN script tag Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -47,20 +47,20 @@ function renderUsers(users) {
|
||||
: `<button class="btn btn-sm btn-ghost" onclick="toggleUser(${u.id}, true)" ${isSelf ? 'disabled title="Cannot disable yourself"' : ''}>Disable</button>`;
|
||||
|
||||
const impersonateBtn = !isSelf
|
||||
? `<button class="btn btn-sm btn-ghost" onclick="impersonateUser(${u.id}, '${u.username}')">Login As</button>`
|
||||
? `<button class="btn btn-sm btn-ghost" onclick="impersonateUser(${u.id})">Login As</button>`
|
||||
: '';
|
||||
|
||||
const deleteBtn = !isSelf
|
||||
? `<button class="btn btn-sm btn-danger" onclick="showDeleteModal(${u.id}, '${u.username}')">Delete</button>`
|
||||
? `<button class="btn btn-sm btn-danger" data-username="${escHtml(u.username)}" onclick="showDeleteModal(${u.id}, this.dataset.username)">Delete</button>`
|
||||
: '';
|
||||
|
||||
return `<tr>
|
||||
<td><strong>${u.username}</strong></td>
|
||||
<td><strong>${escHtml(u.username)}</strong></td>
|
||||
<td>${roleLabel}</td>
|
||||
<td>${statusLabel}</td>
|
||||
<td>${created}</td>
|
||||
<td class="actions" style="display:flex;gap:0.35rem;flex-wrap:wrap">
|
||||
<button class="btn btn-sm btn-ghost" onclick="showResetModal(${u.id}, '${u.username}')">Reset PW</button>
|
||||
<button class="btn btn-sm btn-ghost" data-username="${escHtml(u.username)}" onclick="showResetModal(${u.id}, this.dataset.username)">Reset PW</button>
|
||||
${toggleBtn}
|
||||
${impersonateBtn}
|
||||
${deleteBtn}
|
||||
@@ -115,7 +115,7 @@ async function toggleUser(id, disable) {
|
||||
}
|
||||
}
|
||||
|
||||
async function impersonateUser(id, username) {
|
||||
async function impersonateUser(id) {
|
||||
try {
|
||||
const data = await API.post(`/api/admin/users/${id}/impersonate`, {});
|
||||
// Save admin token so user can return
|
||||
|
||||
Reference in New Issue
Block a user