fix(sicurezza): safeNext blocca backslash (open redirect) + guardia ownership su /admin/edit

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-05 22:34:16 +02:00
parent e2bbc9074f
commit 7211d74d3a
3 changed files with 6 additions and 1 deletions
+1
View File
@@ -1,6 +1,7 @@
// Path interno sicuro per il redirect post-login: deve iniziare con "/", non essere
// protocol-relative ("//"), non puntare alle API. Tutto il resto → home.
export function safeNext(next: string | null): string {
if (next && next.includes('\\')) return '/';
if (!next || !next.startsWith('/') || next.startsWith('//')) return '/';
if (next.startsWith('/api/')) return '/';
return next;
+3 -1
View File
@@ -2,10 +2,12 @@
import Admin from '../../../layouts/Admin.astro';
import PostForm from '../../../components/admin/PostForm.astro';
import { getDb } from '../../../lib/db';
import { getPostById } from '../../../lib/posts';
import { getPostById, canModifyPost } from '../../../lib/posts';
export const prerender = false;
const post = getPostById(getDb(), Number(Astro.params.id));
if (!post) return Astro.redirect('/admin');
const u = Astro.locals.user!;
if (!canModifyPost(u.role, u.id, post)) return Astro.redirect('/admin');
---
<Admin title={`Modifica: ${post.title}`}>
<h1>Modifica articolo</h1>
+2
View File
@@ -14,5 +14,7 @@ describe('safeNext', () => {
expect(safeNext('/api/admin/posts')).toBe('/');
expect(safeNext('javascript:alert(1)')).toBe('/');
expect(safeNext('not-a-path')).toBe('/');
expect(safeNext('/\\evil.com')).toBe('/');
expect(safeNext('/\\/evil.com')).toBe('/');
});
});