# Review package: e2bbc90..7211d74 ## Commits 7211d74 fix(sicurezza): safeNext blocca backslash (open redirect) + guardia ownership su /admin/edit ## Files changed src/lib/safe-next.ts | 1 + src/pages/admin/edit/[id].astro | 4 +++- tests/safe-next.test.ts | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) ## Diff diff --git a/src/lib/safe-next.ts b/src/lib/safe-next.ts index b9b9a6c..1c2e5b3 100644 --- a/src/lib/safe-next.ts +++ b/src/lib/safe-next.ts @@ -1,7 +1,8 @@ // 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; } diff --git a/src/pages/admin/edit/[id].astro b/src/pages/admin/edit/[id].astro index 7789e84..a3a0858 100644 --- a/src/pages/admin/edit/[id].astro +++ b/src/pages/admin/edit/[id].astro @@ -1,14 +1,16 @@ --- 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'); ---

Modifica articolo

diff --git a/tests/safe-next.test.ts b/tests/safe-next.test.ts index 9435af9..c0aeafc 100644 --- a/tests/safe-next.test.ts +++ b/tests/safe-next.test.ts @@ -7,12 +7,14 @@ describe('safeNext', () => { expect(safeNext('/blog/x?y=1')).toBe('/blog/x?y=1'); }); it('rifiuta esterni, protocol-relative, api e vuoti', () => { expect(safeNext(null)).toBe('/'); expect(safeNext('')).toBe('/'); expect(safeNext('//evil.com')).toBe('/'); expect(safeNext('https://evil.com')).toBe('/'); 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('/'); }); });