O vulnerabilitate Next.js în imaginile OG poate executa cod pe serverul tău. Actualizează la 16.3.6.

Vercel a lansat o actualizare de urgență pentru Next.js pe 22 septembrie, și dacă generezi imagini Open Graph din aplicația ta, citește asta înainte de orice altceva astăzi. Actualizarea, versiunile 16.3.6 și 15.5.26, remediază o vulnerabilitate critică de execuție de cod la distanță în next/og, urmărită ca CVE-2026-94545 (advisory GHSA-vcvr-r3jv-pc5j). Scorul CVSS este 9,5. Asta e printre cele mai grave erori pe care le poate avea un framework.
Vulnerabilitatea se află în versiunea Node.js a ImageResponse, utilitarul pe care majoritatea echipelor îl folosesc pentru a construi share card-uri dinamice: micile previzualizări cu titlu și imagine care apar când cineva pune link-ul tău în Slack, LinkedIn sau un chat de grup. Sub capotă, ImageResponse trimite JSX-ul tău la Satori, care îl transformă în SVG, apoi randează acel SVG ca PNG. Cauza principală se află cu un nivel mai jos, în Satori, care are propriul advisory (GHSA-wx4j-mvgx-mqwp): nu escapa anumite valori înainte de a le scrie în SVG. Astfel, o valoare pe care o credeai text simplu putea „ieși” și fi interpretată ca markup SVG activ. Când renderul procesează acel markup, input-ul controlat de atacator poate ajunge să fie executat pe serverul tău.
Ești cu adevărat expus?
Condiția care te face vulnerabil este specifică și merită să fii sincer în privința ei. Ești expus dacă rulezi ImageResponse Node.js (implicit pentru App Router când un route nu optează pentru Edge) și transmiți în imagine o valoare controlată de vizitator. Un cuvânt extras din URL. Un nume de profil. Un parametru din query string. Nu e un pattern exotic. E exact rețeta pe care toată lumea o folosește pentru a face câte un share card per articol. Dacă route-ul tău OG randează doar titluri hardcodate sau valori dintr-o bază de date de încredere, nu ești în zona de risc. Nici implementarea Edge a ImageResponse nu este afectată.
Versiunile afectate sunt Next.js 16.2.0 până la 16.3.5. Remedierea este 16.3.6. Vercel a lansat și 15.5.26 în aceeași zi, dar acea versiune conține doar întăriri de securitate; linia 15.x nu era vulnerabilă la RCE.
Partea care îi prinde pe mulți
Iată unde petrecem mult timp în cadrul angajamentelor de pentesting: actualizarea framework-ului este necesară, dar nu întotdeauna suficientă. npm install next@16.3.6 actualizează Satori pe care Next.js îl include. Nu face nimic pentru un satori sau @vercel/og adăugat în propriul package.json. Vedem asta constant. O echipă actualizează dependența principală, scannerul tot semnalează probleme și nimeni nu înțelege de ce. Dacă folosești Satori direct oriunde, actualizează-l la 0.33.5 sau mai nou separat și verifică ce rezolvă de fapt lockfile-ul tău, nu te baza pe versiunea de nivel superior.
Ce să faci această săptămână
Începe cu un grep în codebase pentru next/og, opengraph-image și twitter-image. Dacă nu apare nimic, poți respira ușurat și programa actualizarea la cadența ta normală. Dacă apare ceva, tratează fiecare din acele route-uri ca accesibil până când l-ai analizat. Pune o singură întrebare per route: poate un vizitator influența vreo valoare care ajunge în imagine? Apoi actualizează la 16.3.6 (sau 15.5.26 pe linia 15), reinstalează ca lockfile-ul să se actualizeze, rebuilduiești și redeployezi. Confirmă versiunea Satori rezolvată în build output, nu doar în package.json.
Dacă nu poți livra astăzi, soluția alternativă declarată de Vercel este simplă, dar funcționează: oprește transmiterea de input neîncredere în imagine. Înlocuiește valoarea dinamică cu un placeholder sigur sau mută route-ul în runtime-ul Edge dacă rulează acolo fără modificări. Niciuna nu e o soluție pe termen lung. Ambele îți câștigă o zi.
Lecția mai mare
Există un tipar aici, același pe care Log4Shell și recenta vulnerabilitate de prototype pollution din axios ni l-au predat. Vulnerabilitățile periculoase sunt rareori în codul tău propriu. Se află la unul sau două niveluri mai jos, într-o bibliotecă larg de încredere pe care un framework o aduce pentru tine. Când construim aplicații cloud-native pentru clienți enterprise, de aceea insistăm pe un software bill of materials real și scanare automată a dependențelor integrată în CI, nu un audit trimestrial. Vrei ca tooling-ul să îți spună „livrezi Satori 0.31, acum e vulnerabil” în dimineața în care apare advisory-ul, nu trei săptămâni mai târziu când un client îți trimite un scan.
Forma injection-to-RCE este și un memento util pentru cum gândești orice renderer, pe backend sau în interiorul unei aplicații mobile. Orice preia input structurat și produce un document (SVG, HTML, un PDF, un payload WebView) este un loc unde „simplu text” poate deveni liniștit „executabil”. În proiectele noastre native iOS și Android aplicăm aceeași regulă pentru orice randează conținut server-driven: escapează la limită și nu presupune niciodată că nivelul de dedesubt a făcut-o pentru tine. Remedierea Satori a fost exact asta — escaparea textului și a valorilor de atribut înainte de a ajunge în SVG. Framework-ul avusese încredere în bibliotecă să facă ceva ce biblioteca nu făcea.
Dacă vrei un al doilea rând de ochi asupra căror route-uri next/og pot fi cu adevărat accesate de un vizitator, ăsta e un lucru de rutină pentru noi. Vezi cum abordăm securitatea aplicațiilor web. Și dacă un advisory critic apărut vineri după-amiaza, cu nimeni sigur care route-uri sunt expuse, sună familiar, hai să vorbim.