Private
Public Access
1
0

Security hardening and fix all compile warnings

Security fixes:
- Validate theme background image URLs against whitelist pattern
- Add board permission check to Socket.IO join-board handler
- Disable raw HTML passthrough in markdown parser (XSS prevention)
- Add UUID validation on avatar and branding route params (path traversal)
- Add security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy)
- Validate webhook URLs (HTTPS only, block internal addresses)
- Add import payload size limit (5MB)
- Remove server uptime from health endpoint
- Make seed password configurable via SEED_ADMIN_PASSWORD env var
- Patch DOMPurify dependency vulnerability via npm audit fix

Warning fixes:
- Convert $state(prop) to $effect.pre sync pattern (state_referenced_locally)
- Add for/id pairings to form labels (a11y_label_has_associated_control)
- Add svelte-ignore for intentional autofocus usage (a11y_autofocus)
- Add ARIA roles to interactive/overlay divs (a11y_no_static_element_interactions)
- Add aria-label to icon-only buttons (a11y_consider_explicit_label)
- Add keyboard handler alongside click events (a11y_click_events_have_key_events)
- Fix non-reactive fileInput declaration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Catherine Renelle
2026-03-07 18:36:47 -05:00
parent 8f79de1df6
commit d418c367cb
37 changed files with 227 additions and 78 deletions
+23 -1
View File
@@ -87,7 +87,29 @@ io.on('connection', (socket) => {
// Track which boards this socket has joined (for cleanup on disconnect)
const joinedBoards = new Set();
socket.on('join-board', (boardId) => {
socket.on('join-board', async (boardId) => {
// Validate boardId format (UUID)
if (typeof boardId !== 'string' || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(boardId)) {
return;
}
// Check board access permission
try {
const board = await prisma.board.findUnique({
where: { id: boardId },
select: { visibility: true, members: { select: { userId: true } } }
});
if (!board) return;
if (board.visibility !== 'PUBLIC') {
if (!user) return;
const isMember = board.members.some((m) => m.userId === user.id);
if (!isMember && user.tenantRole !== 'ADMIN' && user.globalRole !== 'SITE_ADMIN') return;
}
} catch (err) {
logger.error({ err, boardId }, 'Board access check failed');
return;
}
socket.join(`board:${boardId}`);
joinedBoards.add(boardId);