"Sicurezza in Bolt" sono due cose che conviene tenere separate. La prima è il progetto Bolt in sé: cosa incolli nella chat, dove finiscono le variabili d'ambiente, con chi condividi il progetto e dove viene fatto il deploy. La seconda è il codice che Bolt genera, quasi sempre una SPA con Vite e React collegata a Supabase, che porta gli stessi cinque o sei difetti di sempre. Questa guida copre entrambe, con un file di istruzioni perché Bolt applichi le regole a ogni generazione, un prompt di revisione prima del deploy e il modo di verificare il risultato dall'esterno.
Parte 1: proteggere il tuo progetto Bolt
Bolt gira nel tuo browser, e questo cambia dove vivono le chiavi
Bolt esegue l'intero progetto dentro il browser con WebContainers. Non c'è un server tuo mentre sviluppi, quindi qualsiasi chiave che metti in un file .env è nel progetto, e se ha il prefisso VITE_ finisce incorporata nel bundle che viene pubblicato. Per il browser va bene solo con chiavi pubbliche (la anon di Supabase, la publishable di Stripe). Quelle segrete non hanno posto nel frontend: vanno in una Edge Function di Supabase o in una funzione di Netlify, e il client chiama la funzione.
Quello che incolli nella chat finisce nel codice
Se incolli una chiave nella conversazione per "collegare" un servizio, il modello la scrive dove gli serve, di solito in un componente. Da lì viaggia verso tutti i visitatori. La regola: le chiavi pubbliche vanno in .env; quelle segrete nel pannello del servizio che esegue la funzione (Supabase o Netlify), mai nella chat. E se ne hai incollata una per errore, ruotala: la cronologia la conserva anche se la cancelli dal codice.
Condividere, esportare e fare il deploy
Un link di progetto condiviso mostra il codice completo, .env compreso. Prima di condividere, controlla cosa c'è dentro. Se esporti su GitHub, rendi privato il repository e tieni .env nel .gitignore. Il deploy con un clic va su Netlify, su un sottodominio .netlify.app o sul tuo dominio; Netlify dà TLS e reindirizzamento a HTTPS, ma non header di sicurezza, e le variabili d'ambiente di produzione si configurano nel suo pannello, non nel .env del progetto.
Supabase è tuo
L'integrazione di Supabase crea tabelle, policy e funzioni dalla chat. RLS, bucket e impostazioni di Auth restano responsabilità tua, e Bolt commette gli stessi errori di Lovable con le policy. La guida alla sicurezza per Supabase ha tre query SQL per fare l'audit del progetto in un minuto.
Parte 2: i difetti che Bolt mette nel tuo codice
- Chiavi segrete nei componenti. Una chiamata a OpenAI o Stripe da React con la chiave dentro. Cerca
sk_,service_roleeBearernel tuo bundle pubblicato. - Tabelle senza RLS o con policy
using (true). Quando una query fallisce per permessi, il modello apre la policy invece di sistemarla. - Edge Functions senza autenticazione. Il template risponde a chiunque con
Access-Control-Allow-Origin: *; se la funzione spende soldi, chiunque può spenderli. - Controlli solo nell'interfaccia. La pagina di amministrazione si nasconde se non sei amministratore, ma l'API risponde lo stesso.
- Source map in produzione. Alcuni template di Vite portano
build.sourcemap: true; pubblica il tuo codice originale accanto a quello minificato. - Invisibile all'IA e ai motori di ricerca. L'HTML arriva vuoto e i bot di ChatGPT o Perplexity non vedono nulla. Se la landing conta, prerenderizzala o separala. Dettaglio in perché le app create con l'IA sono invisibili all'IA.
- Senza header di sicurezza. Né CSP, né HSTS, né X-Frame-Options. Su Netlify si aggiungono con un file.
Un blocco perché Bolt lo applichi sempre
Bolt legge il file .bolt/prompt del tuo progetto come istruzioni permanenti. Crea il file e incolla questo:
Regole di sicurezza di questo progetto:
- Non mettere mai chiavi segrete nel codice del frontend né in variabili VITE_. Le integrazioni con chiavi segrete vanno in una Edge Function di Supabase o in una funzione di Netlify che legge la chiave dalle sue variabili d'ambiente.
- Ogni tabella nuova ha RLS attivo e una policy esplicita per operazione. Non usare using (true) né with check (true) se non su contenuto pubblico in sola lettura, e avvisami quando lo fai.
- Ogni funzione server verifica il JWT dell'utente, limita Access-Control-Allow-Origin al nostro dominio e valida l'input.
- I permessi di amministratore si controllano in RLS o sul server, mai solo nell'interfaccia.
- I file degli utenti vanno in bucket privati con policy e URL firmati.
- build.sourcemap resta disattivato in produzione.
- Metti titolo, meta description e tag Open Graph reali in index.html.
E gli header per Netlify, in un file public/_headers che viene pubblicato con l'app:
/*
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Un prompt di revisione prima del deploy
Rivedi la sicurezza di questo progetto e non cambiare ancora nulla. Rispondi con una lista:
1. Chiavi o token nel codice del frontend o in variabili VITE_, con file e riga.
2. Tabelle senza RLS e policy con using (true) o with check (true).
3. Funzioni server che non verificano il JWT, che rispondono con Access-Control-Allow-Origin: * o che non validano l'input.
4. Azioni di amministratore protette solo nell'interfaccia.
5. Bucket pubblici con file degli utenti.
6. build.sourcemap attivo e assenza del file _headers.
7. Metadati di index.html ancora quelli del template.
Per ogni punto, proponi la modifica esatta e aspetta la mia conferma.
Verifica il risultato dall'esterno
curl -sI https://tuodominio.com | grep -iE "strict-transport|x-frame|x-content-type"
curl -s https://tuodominio.com | grep -oE '/assets/[^"]+\.js' | head -1
curl -s https://tuodominio.com/assets/index-XXXX.js | grep -oE "sk_live_[A-Za-z0-9]+|service_role|eyJhbGciOi[A-Za-z0-9_-]{20,}" | head -3
curl -sI https://tuodominio.com/assets/index-XXXX.js.map | head -1
L'atteso: header presenti, nessuna chiave nel chunk e un 404 sulla source map. Poi prova l'API di Supabase senza sessione come spiega la guida Supabase. Scanaris fa queste verifiche e una quarantina di altre in 30 secondi: rileva che l'app è fatta con Bolt, cerca segreti nel bundle, controlla source map, header, CORS, cookie e file esposti, prova le tabelle di Supabase senza sessione e verifica se il tuo contenuto è leggibile senza JavaScript. Per ogni errore ti dà un fix prompt da incollare nella chat di Bolt, e può riscansionare ogni giorno, perché una rigenerazione può riportare un difetto già sistemato.
Domande frequenti
Le variabili VITE_ sono private?
No. Vite incorpora nel bundle tutto ciò che inizia con VITE_; è il suo modo di dire "questo è pubblico". Le chiavi segrete non hanno quel prefisso e non si leggono dal frontend.
Posso impostare header di sicurezza su Netlify?
Sì, con il file _headers nella cartella pubblica o con netlify.toml. Netlify li applica al deploy successivo; verifica con curl.
Cosa faccio se ho incollato una chiave segreta nella chat di Bolt?
Ruotala nel servizio di origine anche se l'hai cancellata dal codice: la cronologia del progetto e i deploy precedenti la conservano. Poi aggiungila nel pannello di Supabase o Netlify e chiedi a Bolt di spostare l'integrazione in una funzione.