// ❌ VULNERABIL: Oricine poate șterge orice proiect dacă știe ID-ul
export async function deleteProjectUnsafe(projectId: string) {
"use server";
// Lipsește verificarea sesiunii și validarea inputului!
await db.project.delete({ where: { id: projectId } });
}
// SECURE: Validat, autentificat și autorizat
export async function deleteProjectSafe(projectIdRaw: unknown) {
"use server";
// 1. Validăm tipul de date
const projectId = z.string().uuid().parse(projectIdRaw);
// 2. Verificăm autentificarea
const session = await getSession();
if (!session?.userId) throw new Error("Neautorizat");
// 3. Verificăm dacă userul deține resursa înainte de ștergere
const project = await db.project.findUnique({ where: { id: projectId } });
if (!project || project.ownerId !== session.userId) {
throw new Error("Acces interzis");
}
await db.project.delete({ where: { id: projectId } });
}Săptămâna trecută am făcut un audit pe un app Next.js cu vreo 15.000 de utilizatori activi și m-am luat de cap. Mulți colegi au încă impresia că dacă Next.js e un framework modern și popular, ne protejează implicit de tot ce scrie în manualul OWASP. Spoiler alert: nu o face, ba chiar noile Server Actions deschid niște portițe extrem de stupide dacă nu ești atent la PR-uri.
În 2026, vectorii de atac s-au mutat de la clasicele XSS-uri din client direct în logica de server randată hibrid. Dacă faci review-uri de cod pe fugă și dai doar „Approve” fără să sapi în detalii, riști să lași vulnerabilități masive active în producție.
Server Actions și Broken Access Control (IDOR)
Marea problemă în Next.js-ul modern nu mai este că ne fură cineva cookie-ul de sesiune prin XSS, ci că lăsăm ușa deschisă prin Broken Access Control direct în Server Actions.
De ce se întâmplă asta? Pentru că o acțiune de server (marcată cu "use server") este, la finalul zilei, un endpoint POST public generat automat de Next.js. Dacă ai o funcție de tipul deleteComment(commentId), oricine poate trimite un request HTTP direct către acel endpoint cu un ID arbitrar.
Trade-off-ul este evident: e superb că am scăpat de boilerplate-ul de API routes și scriem cod mai repede, dar am pierdut middleware-ul clasic de autentificare la nivel de rută. Acum, verificarea permisiunilor trebuie făcută manual în interiorul fiecărei acțiuni de server. Dacă în PR vezi o acțiune care modifică date în DB și nu verifică sesiunea userului direct în corpul funcției, dă-i reject instant.
SQL Injection în era ORM-urilor
„Folosim Prisma / Drizzle, n-avem cum să luăm SQL Injection.” Aud asta mult prea des. Este o capcană periculoasă.
Am avut un caz acum câteva luni unde un coleg a trebuit să scrie un query brut (folosind $queryRaw în Prisma) pentru a genera un raport complex cu sortare dinamică. Inputul pentru coloana de sortare venea direct din query parameters, adică din browser, complet nesanitizat. Pentru că granița dintre client și server este atât de fină în Next.js, este extrem de ușor să uiți unde se termină încrederea în inputul utilizatorului. Dacă vezi concatenări de string-uri în query-uri de bază de date la PR, e cod roșu.
CSRF și Route Handlers
Next.js ne protejează automat de atacurile CSRF (Cross-Site Request Forgery) atunci când folosim Server Actions, comparând headerele Origin și Host. E o chestie excelentă introdusă nativ.
Dar ce se întâmplă dacă echipa ta încă folosește Route Handlers clasice (app/api/route.ts) pentru anumite integrări sau pentru că așa s-au obișnuit? Dacă folosiți autentificare bazată pe cookie-uri și nu aveți setat corect flag-ul SameSite: Lax sau Strict pe cookie-ul de sesiune, sunteți expuși total. Orice site malițios deschis de user în alt tab poate face request-uri în numele lui către API-ul vostru.
Checklist rapid pentru următorul PR de Next.js
Când analizezi codul unui coleg (sau pe al tău), pune-ți aceste trei întrebări simple:
- Fiecare funcție cu
"use server"verifică identitatea userului? Nu te baza pe faptul că pagina pe care este randat butonul e protejată. Acțiunea de server poate fi apelată independent. - Inputul din Server Actions este validat riguros? Folosiți librării ca Zod sau Valibot pentru a valida structura datelor primite. Tratează orice parametru ca fiind potențial malițios.
- Folosim
dangerouslySetInnerHTML? Dacă da, textul randat trece printr-un parser de sanitizare precumisomorphic-dompurify?
Securitatea în Next.js nu mai ține de configurări complexe de server sau webpack, ci de atenția la detalii în timpul review-ului de cod. Voi ce soluții folosiți pentru scanarea automată a vulnerabilităților în Server Actions, sau vă bazați doar pe ochiul liber la PR?