Vai al contenuto

La tua app Cursor è sicura?

Cursor è sicuro per app in produzione? Il codice di solito gira bene. Funzionare ed essere protetti sono prove diverse, e una sola parte da sola.

Vlad Tkachenko5 min di lettura
La scheda di controllo sicurezza di Reeve per le app Cursor, con il logo Cursor su una piastrella bianca.

I loghi sono di proprietà dei rispettivi titolari e sono mostrati solo per indicare la compatibilità.

In breve

  • Un'app fatta con Cursor è di solito sicura da eseguire. Se sia sicura da esporre è una prova a parte, e nessuno la esegue al posto tuo.
  • Il codice generato risponde alla domanda che hai fatto. Quali righe un visitatore possa vedere è una domanda che appartiene al database.
  • Il modo consueto in cui una chiave segreta finisce pubblicata: un refactor dal server al browser, poi si aggiunge NEXT_PUBLIC_ o VITE_ per far sparire l'errore.

Cursor ti dà controllo vero (il tuo repository, i tuoi file, il tuo deploy), e questo sposta il punto in cui sta il rischio. Non ti stai chiedendo che cosa abbia fatto un builder al posto tuo. Stai rileggendo molto codice che funziona, in fretta, e decidendo che cosa leggere con attenzione.

Ecco il punto che guida dopo guida racconta male: chiedersi se l'IA scriva codice non sicuro è la domanda sbagliata. Il codice generato è scritto per soddisfare quello che hai chiesto. «Carica gli ordini dell'utente» è soddisfatto da codice che carica ordini. In quella frase non c'è scritto di chi, quindi nella risposta non c'è nulla che lo decida, e il posto a cui quella decisione appartiene non è il file che stai rileggendo.

Funzionare ed essere protetti sono due prove diverse

Solo una delle due parte da sola.

Pensala come un negozio. La tua app è la vetrina: ogni pagina che costruisci viene consegnata per intero a ogni visitatore, perché un browser non può disegnare ciò che non gli è stato inviato. Il tuo database è il magazzino, un edificio separato su internet con la sua serratura e il suo indirizzo.

Quando avvii la tua app e funziona, hai messo alla prova la vetrina: per te compaiono le cose giuste sulle schermate giuste. Non hai messo alla prova la serratura. Il magazzino è raggiungibile direttamente, senza passare dal tuo negozio, e il fatto che la tua app si carichi correttamente non dice nulla su che cosa restituisca a chi salta la porta d'ingresso.

È la prova che non parte mai da sola, in nessun progetto, generato o scritto a mano. Diventa più facile da saltare quando il codice arriva più in fretta di quanto tu riesca a leggerlo.

Dove vanno storte le chiavi in un progetto Cursor

Nel passaggio dal server al browser, quasi sempre.

Si chiamano entrambe chiavi API. Solo una delle due è mai stata pensata per essere letta.

Esistono due tipi di credenziale e si somigliano quasi in tutto. Una chiave pubblicabile nomina il tuo progetto e nient'altro (sb_publishable_… nei progetti Supabase nuovi, anon in quelli più vecchi), ed è progettata per vivere in un browser. Una chiave segreta, sb_secret_… o la più vecchia service_role, ignora ogni regola tu abbia scritto e può leggere e scrivere ogni riga che possiedi.

La sequenza che ne pubblica una è ordinaria. Codice che usava una chiave segreta sul server viene rifattorizzato in un componente che gira nel browser. Il valore torna undefined, quindi la variabile viene rinominata con il prefisso che lo strumento di build vuole (NEXT_PUBLIC_ in Next.js, VITE_ in Vite), e l'app comincia a funzionare. La documentazione di Vite è esplicita su che cosa fa quel prefisso: quei valori finiscono nel tuo codice sorgente al momento della build.

.gitignore qui non aiuta. Governa ciò che finisce nel repository, e l'output della build viene generato dopo. Se preferisci essere sicuro di quale delle tue chiavi sia quale, esiste un controllo da un minuto.

Il controllo che appartiene al database

La Row Level Security, se i tuoi dati sono in Supabase, è un interruttore per tabella che decide riga per riga chi può leggere cosa.

La tua app e un estraneo bussano alla stessa porta. È l'impostazione a decidere chi entra, non le schermate della tua app.

Questa è la risposta al problema del «carica gli ordini». Invece di fidarsi che ogni query nel codice filtri correttamente, il database rifiuta di restituire righe a cui il visitatore non ha diritto, qualunque cosa dicesse la query e chiunque l'abbia scritta. Una regola, applicata nell'unico punto da cui ogni richiesta deve passare.

Due dettagli decidono se ce l'hai. Supabase attiva la Row Level Security per impostazione predefinita sulle tabelle create nel Table Editor del pannello, e non su quelle create eseguendo SQL, che è il modo in cui le crea un file di migrazione. E l'impostazione accende soltanto il controllo; chi passa lo decide la policy che sta dietro, e una policy può permettere comunque a tutti.

Come controllare il tuo progetto Cursor in una decina di minuti

Cerca nell'output della build, non nei sorgenti. Compila l'app, poi cerca nei file generati service_role, sb_secret_ e sk_live_. Tutto ciò che salta fuori è pubblicato. È più rapido e più onesto che leggere i sorgenti, perché è ciò che i visitatori ricevono davvero.

Leggi il tuo file d'ambiente cercando i prefissi. Ogni variabile NEXT_PUBLIC_ o VITE_ è pubblica per costruzione. Per ognuna, chiediti se la stamperesti in homepage.

Apri Authentication → Policies in Supabase. Qualsiasi tabella che mostri la Row Level Security come disattivata è leggibile da chiunque possieda l'indirizzo del tuo progetto, che sta dentro la tua app.

E poi guarda da fuori. La nostra scansione gratuita fa quest'ultimo passo per te: legge il tuo sito dal vivo come un visitatore e ti dà un voto in una ventina di secondi, senza account: scansiona la tua app.

Cosa fare

  • Un'app che funziona ha superato una prova. Se il database rifiuti un estraneo è una prova a parte che nessuno esegue al posto tuo.
  • Il codice generato risponde alla domanda che hai fatto. «Quali righe può vedere questa persona» è una domanda che appartiene al database.
  • Il modo comune in cui una chiave segreta finisce pubblicata è un refactor dal server al browser seguito da una rinomina di prefisso.
  • .gitignore protegge il tuo repository, non l'output della build.
  • Su Supabase, le tabelle create eseguendo SQL partono senza Row Level Security, e attivarla lascia ancora ogni riga leggibile finché una policy non dice altro.

Compila il tuo progetto e cerca service_role e sk_live_ nell'output prima di qualsiasi altra cosa; richiede un minuto e la risposta non è ambigua. Dopo, la checklist di sicurezza in 10 minuti è la strada più breve attraverso il resto.

Cosa può davvero andare storto con un'app creata con Cursor

Niente di tutto questo significa che hai fatto qualcosa di sbagliato: sono i normali effetti collaterali del lasciare che l'IA scriva codice in fretta. Ecco cosa vale la pena controllare:

  • Una chiave segreta scritta direttamente nel codice

    Quando l'IA collega un servizio, a volte mette la chiave direttamente nel codice per farlo funzionare, e se quel codice gira nel browser, chiunque può leggerla. Alcune chiavi devono essere pubbliche e va bene; Reeve legge il codice caricato della tua app, trova tutte le chiavi e ti dice quali sono sicure e quali vanno spostate sul server.

  • Un .env committato o una cartella .git esposta

    Le chiavi dovrebbero vivere in un file .env che non viene mai pubblicato. Ma è facile committare .env per sbaglio, o pubblicare la cartella nascosta .git, così tutta la cronologia, chiavi comprese, diventa scaricabile. Reeve controlla se l'uno o l'altra è raggiungibile dall'esterno.

  • Il tuo database lasciato aperto (RLS disattivato)

    Se la tua app conserva dati (spesso in Supabase o in un altro Postgres), c'è una regola (Row Level Security) su chi può leggere o modificare ogni riga. Se è disattivata, le tue tabelle possono essere aperte a chiunque trovi l'indirizzo. È il problema serio più comune, ed è invisibile a meno che tu non controlli.

  • Archiviazione di file pubblica

    Se la tua app accetta caricamenti, questi vivono in «bucket» di archiviazione. Un bucket pubblico significa che chiunque può elencare o scaricare ciò che c'è dentro, così un file privato può finire visibile a tutti. Reeve controlla se i tuoi bucket sono elencabili; non scarica mai i file di nessuno.

  • Source map lasciate attive

    Una «source map» rivela il codice originale della tua app a chiunque guardi. Utile mentre costruisci, ma in produzione dà agli estranei una copia leggibile di come funziona la tua app e rende altre falle più facili da trovare. Vale la pena sistemarla. Reeve controlla se le tue sono esposte.

  • Header di sicurezza mancanti ed endpoint aperti

    Piccole impostazioni che dicono ai browser come proteggere i tuoi visitatori, più il fatto che i tuoi endpoint di dati rispondano a chiunque o a qualsiasi sito. Minori da soli; insieme si sommano. Reeve segnala cosa manca.

Cos'è Reeve, e cosa non è

Reeve è un controllo gratuito, in sola lettura, dall'esterno, come un ispettore che prova le porte senza entrare. È veloce e coglie gli errori comuni ad alto impatto. Non è un audit di sicurezza completo, e un voto pulito non è una garanzia. Significa che le porte ovvie sono chiuse.

Cursor è un editor, non un hosting, quindi non pubblica né sorveglia la tua app per te; di più ricade su di te e sul codice che l'IA ha prodotto. Gli stessi strumenti di Cursor possono aiutare a rivedere il codice man mano, e se usi Supabase il suo consulente segnala i problemi del database. Cosa aggiunge Reeve: una vista dall'esterno dell'app che hai davvero pubblicato, con parole semplici su cui puoi agire. E se preferisci non pensarci, possiamo tenerla d'occhio noi per te.

Vuoi che sia gestito, non solo controllato?

Reeve Care continua a tenere d'occhio la tua app, fa il backup dei tuoi dati e ti aiuta a sistemare le cose quando si rompono, così puoi continuare a creare invece di preoccuparti.

Scopri Reeve Care

FAQ

Il codice scritto dall'IA di Cursor è sicuro?

Può essere buon codice, ma «scritto dall'IA» non significa «controllato per la sicurezza». L'IA ottimizza per far funzionare le cose, il che a volte significa una chiave nel posto sbagliato o una regola del database mancante. L'unico modo di saperlo è controllare cosa è esposto. Reeve lo fa gratis in circa 20 secondi.

Penso di aver committato un file .env. È pericoloso?

Può esserlo, se il file (o la cartella nascosta .git) è raggiungibile sul tuo sito pubblicato, perché può contenere chiavi attive. Reeve controlla dall'esterno se l'uno o l'altra è scaricabile, così sai se devi ruotare quelle chiavi.

Come faccio a sapere se la mia app Cursor sta perdendo chiavi di API?

La causa abituale è una chiave scritta direttamente in codice che gira nel browser. Reeve legge il codice caricato della tua app, trova tutte le chiavi e ti dice quali sono sicure da rendere pubbliche e quali vanno spostate sul server, senza conservare i valori reali.

Scansionare la mia app cambierà qualcosa?

No. Reeve guarda solo ciò che è già pubblico dall'esterno. Non accede mai, non cambia mai nulla e non scarica mai i tuoi file. In sola lettura, come controllare se una porta è chiusa a chiave senza entrare.

Cursor scrive codice non sicuro?

È la domanda sbagliata da fare a qualsiasi assistente, compreso uno umano. Il codice generato è scritto per soddisfare quello che hai chiesto, e «fai caricare gli ordini a questa pagina» è soddisfatto da codice che carica tutti gli ordini. Nella richiesta non c'era scritto quali, quindi nella risposta non c'è nulla che lo decida. Comunque tu formuli la richiesta, la regola su chi può leggere quali righe deve vivere nel database.

Il mio file .env è in .gitignore. Sono coperto?

Per il tuo repository, in gran parte. Ma .gitignore non ha alcun effetto su ciò che il tuo strumento di build pubblica. Una variabile con prefisso per il browser (NEXT_PUBLIC_ in Next.js, VITE_ in Vite) viene compilata nel JavaScript che i tuoi visitatori scaricano, ovunque fosse conservata, e resta nella cronologia delle versioni se il file è mai stato committato prima che la regola esistesse.

Come controllo che cosa espone davvero la mia app, invece di leggere il codice?

Carica il tuo sito, apri i DevTools del browser e guarda la scheda Rete mentre la pagina si carica. Tutto quello che compare lì è ciò che riceve un visitatore. Leggerlo così richiede qualche minuto e dice più della lettura dei sorgenti, perché è esattamente la vista che ha una persona esterna.

Scritto da

Vlad Tkachenko

Fondatore di Reeve

Passo le giornate a guardare app costruite con Lovable, Bolt, v0, Cursor e Replit, e la breve lista di errori che vi ricompaiono di continuo.

Altro sull'autore

Creata altrove? Abbiamo lo stesso resoconto onesto per:

← Vedi tutte le guide sulla sicurezza dei creatori

Controllo esterno automatizzato, non un audit completo. L'assenza di risultati non è una garanzia di sicurezza.