Cosa è successo
Stando al resoconto di SafeState sull'analisi dei ricercatori, l'attacco si è svolto più o meno così:
- Il sito di Polymarket caricava uno script di real-user monitoring dalla CDN di DebugBear. È una configurazione normale: migliaia di siti fanno lo stesso con decine di fornitori.
- L'attaccante ha sostituito quel file con JavaScript malevolo. Dato che il browser lo scaricava ogni volta direttamente dal fornitore, ogni visitatore ha ricevuto subito la nuova versione.
- Lo script verificava la presenza di una sessione Polymarket attiva, leggeva dati dell'account, dettagli del wallet e credenziali delle API di trading dallo storage del browser, e poi usava il flusso di firma di Polymarket stesso per spostare posizioni o vendere asset verso un wallet dell'attaccante.
Il dettaglio su cui vale la pena soffermarsi: i ricercatori hanno osservato che hardware wallet e password robuste non sono serviti a nulla, perché lo script non ha mai avuto bisogno di una chiave privata. Agiva come l'utente loggato, dall'interno della sua stessa sessione nel browser.
La correzione di Polymarket, secondo lo stesso report, è stata un commit in produzione che ha rimosso lo script del fornitore. Il trading è ripreso il pomeriggio stesso. SafeState nota anche che non era il primo incidente legato a script di fornitori a colpire la piattaforma quest'anno.
Perché riguarda la tua app
Un tag script che punta a cdn.some-vendor.com gira con gli stessi poteri del tuo codice. Può leggere il DOM, leggere localStorage e sessionStorage, chiamare la tua API con le credenziali dell'utente e cambiare ciò che la pagina mostra. Non c'è alcuna sandbox tra "il tuo codice" e "lo snippet di analytics che hai incollato nella settimana del lancio".
Questo vale soprattutto per le app rilasciate in fretta e per quelle costruite con l'AI, perché:
- Gli script si accumulano. Ogni prompt del tipo "aggiungi analytics", "aggiungi una chat", "aggiungi l'error tracking" tende ad aggiungere un altro tag. Pochi li rimuovono in seguito.
- I token vivono nello storage del browser. Molti template di partenza tengono il token di sessione o dell'API in localStorage, dove qualsiasi script della pagina può leggerlo.
- Di solito manca una Content-Security-Policy. Senza, qualsiasi script iniettato o sostituito può caricare altro codice da qualunque origine e inviare dati ovunque.
Non puoi verificare le pipeline di build dei tuoi fornitori. Puoi però limitare i danni che uno script malevolo può fare.
Come controllare la tua app
1. Elenca tutti gli script caricati dalle tue pagine. Apri la tua app, poi i DevTools, scheda Network, filtra per JS e ricarica. Oppure esegui questo nella console su ogni pagina importante:
[...document.scripts].map(s => s.src || '(inline)').filter(Boolean)Annota ogni dominio che non è tuo. Fallo anche sulle pagine dopo il login, non solo sul sito marketing. I tag manager possono caricare altri script che non compaiono nel sorgente HTML.
2. Controlla quali di quei tag hanno un attributo integrity. Nella console:
[...document.querySelectorAll('script[src]')]
.filter(s => !s.src.startsWith(location.origin))
.map(s => ({ src: s.src, sri: !!s.integrity }))3. Guarda gli header di risposta. Esegui curl -sI https://yourapp.com e cerca Content-Security-Policy. Se manca, o contiene script-src * oppure 'unsafe-inline' senza nonce, non sta limitando granché.
4. Controlla dove vive la tua sessione. Nei DevTools, guarda in Application sotto Local Storage e Session Storage. Se lì vedi un access token, un refresh token o una API key, qualsiasi script della pagina può leggerlo, ed è esattamente ciò che ha fatto il payload di Polymarket.
Come risolvere
Rimuovi ciò che non ti serve. È il passo che rende di più. Le raccomandazioni di SafeState per gli operatori partono proprio dal tenere un inventario degli script di terze parti e dal togliere i tag non essenziali dalle pagine dell'account, del checkout e delle transazioni. Le tue pagine di login, fatturazione e impostazioni raramente hanno bisogno di uno strumento di heatmap.
Fissa la versione e verifica ciò che tieni con Subresource Integrity (SRI). Se un fornitore offre file versionati, punta a una versione specifica e aggiungi un hash. Se il file cambia, il browser si rifiuta di eseguirlo:
<script
src="https://cdn.example-vendor.com/sdk/4.2.1/sdk.min.js"
integrity="sha384-REPLACE_WITH_REAL_HASH"
crossorigin="anonymous"></script>Genera tu stesso l'hash a partire dal file esatto che hai esaminato:
curl -s https://cdn.example-vendor.com/sdk/4.2.1/sdk.min.js \
| openssl dgst -sha384 -binary | openssl base64 -ATieni presente il compromesso: SRI rompe gli script che i fornitori aggiornano sul posto a un URL senza versione, cosa comune per gli snippet di monitoraggio e analytics. Per questi, puoi ospitare in proprio una copia fissata che aggiorni deliberatamente, oppure accettare che ti stai fidando del file live del fornitore e tenerlo lontano dalle pagine sensibili.
Aggiungi una Content-Security-Policy. La CSP dice al browser quali origini possono servire script e verso quali origini la pagina può inviare dati. Un punto di partenza per un'app Next.js o Express potrebbe essere questo:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example-vendor.com;
connect-src 'self' https://api.yourapp.com;
frame-ancestors 'none';
base-uri 'self';
object-src 'none'Sii realista su cosa ti offre la CSP in questo caso: se il dominio del fornitore stesso è consentito, la CSP non fermerà un file malevolo servito da lì. Quello che fa è impedire a quello script di caricare codice da nuovi domini o di inviare i dati rubati a endpoint arbitrari che non sono in connect-src. Introducila prima con Content-Security-Policy-Report-Only, così vedi cosa si rompe. La nostra guida su come aggiungere una Content-Security-Policy ti accompagna passo per passo.
Metti i token di sessione fuori dalla portata di JavaScript. Sposta i token di sessione in cookie con i flag HttpOnly, Secure e SameSite, così gli script della pagina non possono leggerli. Non impedirà a uno script malevolo di fare richieste a nome dell'utente finché la pagina è aperta, ma impedisce che i token vengano sottratti e riutilizzati altrove. Vedi i flag dei cookie Secure, HttpOnly e SameSite.
Tieni pulite le chiavi del tuo frontend. Se uno script può leggere il tuo bundle, può leggere qualsiasi segreto ci hai messo dentro, e i bot stanno già dando la caccia a chiavi trapelate e file .env. Leggi la nostra guida sulle API key esposte nel JavaScript lato client, assicurati di non distribuire source map in produzione e, se hai già avuto uno spavento, il nostro articolo su come ruotare i segreti della tua app senza downtime spiega come fare pulizia.
Checklist finale
Prima di chiudere i DevTools, assicurati di:
- Elencare ogni script di terze parti sulle pagine pubbliche e su quelle dopo il login.
- Rimuovere gli script che non usi più, soprattutto dalle pagine di login, fatturazione e account.
- Fissare le versioni e aggiungere hash di integrity dove i fornitori lo supportano.
- Ospitare in proprio gli script che non si possono fissare, o tenerli lontani dalle pagine sensibili.
- Distribuire una Content-Security-Policy con script-src e connect-src restrittivi.
- Tenere i token di sessione in cookie HttpOnly, non in localStorage.
- Ripetere questo audit ogni volta che qualcuno (o qualche agente AI) aggiunge un nuovo tag.
Scopri a che punto sei
Se vuoi un punto di partenza rapido, AppSafe controlla i tuoi security header, compreso se è impostata una Content-Security-Policy, e la sua scansione completa verificata esamina problemi del frontend come Subresource Integrity e librerie JavaScript vulnerabili. Puoi vedere com'è fatto un report nel report di esempio, oppure abbinare questo articolo alla nostra checklist pre-lancio per app costruite con l'AI.
Polymarket ha individuato la causa entro circa un'ora dallo stop del trading. Molti piccoli team impiegherebbero molto di più ad accorgersi di uno script modificato. Esegui una scansione gratuita con AppSafe sulla tua app oggi e scopri a che punto sei.
