Breșa Vercel 2026: Un singur angajat, o extensie, infrastructura unei companii întregi

Aprilie 2026. Un singur angajat Vercel folosea un tool AI de productivitate — Context.ai — pentru a-și optimiza fluxul de lucru. Nimic ieșit din comun. Și totuși, acel tool, compromis cu o lună înainte, a devenit punctul de intrare într-un atac care a expus variabile de mediu din proiecte Vercel, a atras atenția grupului ShinyHunters și s-a soldat cu o cerere de răscumpărare de 2 milioane de dolari. Un lanț de dependențe invizibile, o colecție de scope-uri OAuth prea generoase și câteva token-uri stocate neglijent — atât a fost nevoie.
Timeline-ul atacului: De la Context.ai la ShinyHunters
- Martie 2026 — Atacatorii compromit infrastructura Context.ai, un tool AI third-party folosit de zeci de echipe de development. Breșa trece inițial neobservată.
- Săptămâna 1-2 aprilie — Din baza de date Context.ai, atacatorii extrag token-uri OAuth stocate în AWS-ul platformei. Printre ele, un token Google Workspace aparținând unui angajat Vercel cu drepturi extinse.
- Săptămâna 2 aprilie — Folosind token-ul Google Workspace, atacatorii accesează contul angajatului și pivotează spre integrările conectate, inclusiv accesul la Vercel prin SSO.
- Mijlocul lunii aprilie — Odată în interiorul contului Vercel, atacatorii iterează prin proiectele accesibile și citesc variabilele de mediu care nu sunt marcate explicit ca 'sensitive' — acestea nu sunt criptate cu același nivel de protecție în UI.
- Sfârșitul lunii aprilie — ShinyHunters revendică public atacul pe forumuri underground, publică un sample de date și cer 2 milioane de dolari pentru ștergerea datelor exfiltrate.
Anatomia tehnică a breșei: Cum arată lanțul de atac
Breșa nu a fost un atac sofisticat de tip zero-day. A fost un lanț de decizii arhitecturale slabe, exploatate metodic. Context.ai, ca orice tool de productivitate AI, cerea la autentificare un set de scope-uri OAuth Google — acces la calendar, Gmail, Drive, uneori și la Google Workspace Admin în funcție de planul ales. Aceste token-uri, după autentificare, erau stocate server-side în baza de date AWS a platformei pentru a permite funcționalități asincrone (rezumate automate, acțiuni programate etc.). Problema: token-urile de refresh OAuth, dacă nu sunt criptate individual sau rotite frecvent, rămân valide mult timp. Când AWS-ul Context.ai a fost compromis — fie printr-o configurare greșită a unui S3 bucket, fie printr-o vulnerabilitate în aplicație — atacatorii au obținut acces la un dump de token-uri active. Fiecare token era, în esență, o cheie digitală spre contul unui utilizator real, fără parolă, fără 2FA.
Pivotarea spre Vercel a fost posibilă deoarece angajatul folosea Google SSO pentru a se autentifica în Vercel. Token-ul Google valid = sesiune Vercel validă. Din acel moment, atacatorul naviga în dashboard-ul Vercel ca un utilizator legitim. Vercel stochează variabilele de mediu în două categorii: cele marcate ca 'sensitive' (criptate end-to-end, nevizibile după salvare) și cele standard (vizibile în UI pentru membrii cu acces). Variabilele standard — chei API, connection strings, feature flags — erau accesibile direct. Un script simplu care itera prin proiecte și apela API-ul Vercel cu token-ul de sesiune era suficient pentru a exfiltra sute de variabile în câteva minute.
De ce OAuth nu e vinovatul — și de ce contează distincția
Prima reacție a multor developeri la acest tip de incident este să pună vina pe OAuth. Greșit. Protocolul OAuth 2.0 a funcționat exact cum a fost proiectat: a emis un token cu scope-urile solicitate, token-ul a fost folosit pentru a accesa resursele autorizate. Nicio vulnerabilitate în protocol. Problema reală are trei componente distincte: gestiunea scope-urilor de către aplicația third-party (Context.ai a cerut mai mult decât era necesar — principiul least privilege încălcat), stocarea token-urilor de către vendor (token-urile de refresh ar trebui criptate individual, cu chei derivate per-user, nu stocate în plaintext sau cu o singură cheie master), și absența revocării automate (un token care nu a fost folosit săptămâni întregi ar trebui invalidat automat). Ca developer care integrează OAuth în aplicații proprii, lecția nu e să eviți OAuth — e să înțelegi că securitatea protocolului nu înlocuiește securitatea implementării.
8 Vectori prin care îți poți pierde token-ul OAuth
- XSS (Cross-Site Scripting)
Dacă stochezi token-ul în localStorage și aplicația ta are o vulnerabilitate XSS, un atacator poate exfiltra token-ul cu o singură linie de JavaScript. Cod vulnerabil: localStorage.setItem('token', accessToken) urmat de orice input neescapat redat în DOM. Cod sigur: stochează token-ul în cookie HttpOnly, SameSite=Strict, Secure — inaccesibil din JavaScript. Alternativ, folosește un BFF (Backend for Frontend) care menține token-ul server-side și emite propriile cookie-uri de sesiune.
- Compromiterea serverului (Server Compromise)
Exact scenariul Context.ai. Token-urile stocate în baza de date sunt expuse dacă serverul e compromis. Cod vulnerabil: db.tokens.insert({ userId, refreshToken }) — token în plaintext. Cod sigur: criptează individual fiecare token înainte de stocare folosind o cheie derivată din secretul utilizatorului — const encrypted = encrypt(refreshToken, deriveKey(userSecret, userId)). Chiar dacă baza de date e exfiltrată, token-urile individuale rămân inutilizabile fără cheile per-user.
- MITM (Man-in-the-Middle)
Un atac MITM pe o conexiune neprotejată poate intercepta token-ul din header-ul Authorization. Cod vulnerabil: orice request HTTP (fără S) care include Authorization: Bearer . Cod sigur: enforced HTTPS everywhere, HSTS cu preload, Certificate Pinning în aplicații mobile. La nivel de server: Strict-Transport-Security: max-age=63072000; includeSubDomains; preload. Nu uita: redirecturile HTTP→HTTPS nu sunt suficiente — primul request poate fi interceptat.
- CSRF (Cross-Site Request Forgery)
Relevant mai ales în flow-ul de autorizare OAuth: un atacator poate injecta un authorization code malițios dacă state parameter-ul nu e validat. Cod vulnerabil: ignorarea parametrului state în callback sau generarea lui predictibilă (state=userId). Cod sigur: generează un state criptografic random (crypto.randomBytes(32).toString('hex')), stochează-l în sesiunea server-side și validează-l strict la callback. Fără match exact → respinge request-ul, indiferent de restul parametrilor.
- Malware și extensii de browser
Extensiile de browser cu permisiuni largi pot citi cookie-urile sau localStorage din orice tab. Un malware local poate dumpa token-urile din memoria browserului. Mitigare: principiul least-privilege pentru extensii instalate, audit periodic al extensiilor cu acces la 'all sites', utilizarea browserelor de lucru separate de cel personal, și EDR (Endpoint Detection and Response) pe mașinile care accesează sisteme critice. La nivel de aplicație: token binding și DPoP (Demonstrating Proof of Possession) leagă token-ul de clientul specific — chiar dacă e furat, nu poate fi folosit dintr-un alt context.
- Device Compromise
Un device compromis înseamnă că toate token-urile stocate pe el — în keychain, în browser profile, în fișiere de configurare — sunt expuse. Cod vulnerabil: stocarea token-urilor în fișiere plaintext (~/.config/app/token) sau în variabile de mediu persistente în shell history. Cod sigur: folosește system keychain (Keychain pe macOS, Credential Manager pe Windows, libsecret pe Linux) pentru stocarea secretelor locale. La nivel organizațional: MDM (Mobile Device Management), disk encryption enforced, și remote wipe capabilities pentru device-urile compromise.
- Phishing OAuth (Consent Phishing)
Atacatorul creează o aplicație OAuth malițioasă cu un nume convingător ('Vercel Analytics Pro', 'GitHub Backup Tool') și convinge utilizatorul să îi acorde consimțământul. Aplicația primește token-uri reale cu scope-urile solicitate. Cod de detecție: auditează periodic aplicațiile autorizate în contul Google/GitHub/Azure AD al organizației. La nivel de politică: în Google Workspace Admin, poți restricționa ce aplicații third-party pot solicita acces OAuth (Admin Console → Security → API Controls → App Access Control). Whitelist explicit aplicațiile aprobate, blochează restul.
- Logs Leak
Token-urile ajung accidental în loguri când sunt incluse în URL-uri (query parameters) sau în request bodies logate integral. Cod vulnerabil: console.log('Request:', req.url) când URL-ul conține ?access_token=xyz, sau logging middleware care loghează headers inclusiv Authorization. Cod sigur: niciodată nu transmiți token-uri ca query parameters (folosește header Authorization), și filtrează explicit câmpurile sensibile în logging middleware — const sanitized = omit(headers, ['authorization', 'cookie', 'x-api-key']). Verifică și că Sentry, Datadog sau alte tools de observabilitate nu captează request bodies cu date sensibile.
Concluzie: Securitatea nu înseamnă să nu fii spart
Breșa Vercel 2026 nu e o poveste despre un protocol spart sau un hacker genial. E o poveste despre suprafețe de atac ignorate și despre iluzia că securitatea unui vendor terț e responsabilitatea lui, nu a ta. Ca developer, fiecare tool la care îi acorzi acces OAuth devine o extensie a suprafeței tale de atac. Fiecare token pe care îl stochezi neglijent e o ușă pe care o lași deschisă.
Scopul securității nu este să fii imposibil de spart — e ca atunci când ești spart, damage-ul să fie minim, detectabil rapid și reversibil. Least privilege, token rotation, sensitive marking și audit logs nu sunt features opționale. Sunt diferența dintre un incident de securitate și un dezastru de business.