Cos'è e perché conta
Quando Claude Code finisce un lavoro e ti dice «fatto, test passati», sembra la fine della storia. Non lo è. I test verdi ti dicono una cosa sola: il codice fa quello che i test controllano. E i test controllano quello che è stato chiesto. Se hai chiesto «fammi salvare un ordine», il test verifica che l'ordine si salvi. Nessuno ha chiesto cosa succede se lo salva qualcuno senza login, o se lo salva a nome di un altro utente.
Per questo «passa i test» non vuol dire «è sicuro». Un'app può superare tutti i suoi test e intanto far leggere i dati di un utente a un altro, accettare due volte lo stesso pagamento o lasciare una chiave segreta nella parte che gira nel browser, dove chiunque la può leggere.
Lo dice anche uno studio uscito su arXiv il 10 ottobre 2026, «Last Secure Code Benchmark: Is the Code You Vibe Secure?». Ha messo alla prova sei agenti di programmazione tra i più avanzati. Il loro codice supera i test di funzionamento nel 73,6–91,3% dei compiti, a seconda dell'agente. Ma anche il migliore dei sei scrive codice che funziona ed è sicuro solo nel 25,1% dei compiti.
Chiedere alla stessa sessione di ricontrollare serve a poco: ha appena scritto quel codice e sa perché l'ha fatto così. Quello che faccio io è aprire una seconda sessione e darle un ruolo preciso, l'attaccante. Non sa niente di come è nato il codice, vede solo le modifiche e ha un compito: trovare come romperle. Non le chiedo se va bene. Le chiedo dove cede.
Perché conta: se costruisci un'app senza essere uno sviluppatore, questi buchi non li vedi rileggendo il codice. E se non li cerca nessuno, il primo a trovarli è un utente.
1. Il prompt dell'attaccante
Lo incollo nella seconda sessione così com'è, quando la prima ha finito e i test sono verdi.
Sei un attaccante, non un revisore gentile. Questo codice passa i test: non mi interessa, i test controllano solo quello che è stato chiesto. Il tuo compito è uno solo: trova come rompere quello che è stato appena fatto. Guarda solo le modifiche: lancia git status e git diff HEAD (mostra anche quelle già in stage), e leggi per intero i file nuovi che git status elenca (il diff non li mostra). Cerca: - chi può chiamarla: cosa succede senza login, con il login di un altro utente, chiamando l'indirizzo direttamente; - dati sbagliati: campi vuoti, testi lunghissimi, caratteri strani, numeri negativi, tipi sbagliati, la stessa richiesta mandata due volte; - chiavi in chiaro: password, token o chiavi segrete scritte nel codice, nei log, nei messaggi di errore o nella parte che gira nel browser; - permessi: chi può leggere, modificare o cancellare dati che non sono suoi; - casi limite: liste vuote, rete lenta, due utenti nello stesso momento. Per ogni problema scrivi: dove (file e riga), come lo rompo (i passi esatti), cosa succede, gravità (alta, media, bassa). Ordina dal più grave. Non correggere niente e non modificare i file: voglio solo il rapporto.
Perché è scritto così, riga per riga.
- «Sei un attaccante, non un revisore gentile»: un revisore gentile cerca di capire il codice e alla fine tende a promuoverlo. Un attaccante parte dall'idea che un buco ci sia e va a cercarlo.
- «Lancia git status e git diff HEAD»: git diff da solo mostra le modifiche non ancora messe in stage, cioè non ancora segnate con git add per il prossimo commit. git diff HEAD le confronta tutte con l'ultimo commit, segnate o no. I file che git non segue ancora però non compaiono nemmeno lì: li elenca git status, e per questo il revisore li legge per intero.
- «Chi può chiamarla»: una pagina può nascondere un pulsante a chi non ha il permesso, ma se l'indirizzo che quel pulsante chiama risponde a chiunque, il pulsante nascosto non protegge niente. Per questo il prompt chiede di chiamare l'indirizzo direttamente.
- «Come lo rompo (i passi esatti)»: con i passi puoi controllare tu se il problema c'è davvero, e dopo la correzione rifarli per vedere se è sparito. Un «potrebbe esserci un rischio» non lo verifichi.
- «Non correggere niente e non modificare i file»: chi attacca segnala e basta. Le correzioni le fa la sessione che ha scritto il codice, così sai sempre chi ha cambiato cosa.
2. Come lo uso
- La prima sessione dice «fatto, test passati». Non le chiedo di ricontrollarsi.
- Apro un terminale nuovo nella stessa cartella e lancio claude: una sessione nuova, che non ha visto la conversazione.
- Incollo il prompt prima del commit, così git status e git diff HEAD mostrano solo il lavoro appena fatto. Se ho già fatto il commit, le indico io i file.
- Porto il rapporto alla prima sessione e faccio correggere partendo dalle gravità alte. Per ogni problema serio chiedo anche un test che lo riproduca, così la prossima volta lo controlla il test.
Dal rapporto alle correzioni
Alla prima sessione passo il rapporto con questo prompt:
Ecco il rapporto di un'altra sessione che ha cercato di rompere il tuo lavoro: [incolla il rapporto]. Parti dai problemi di gravità alta, uno alla volta. Per ognuno prima scrivi un test che lo riproduce e controlla che fallisca, poi correggi e controlla che il test passi. Dimmi cosa hai cambiato e come l'hai verificato. Le gravità basse non toccarle: le decido io.
Il test che fallisce prima della correzione è il pezzo che conta. Ti dice che il problema c'era davvero e non era un'idea del revisore. E resta nel progetto: se una modifica futura riapre lo stesso buco, quel test diventa rosso.
Se vuoi essere sicuro che non tocchi niente
Nel prompt c'è scritto di non modificare i file, ma resta una richiesta. Se voglio un blocco vero, apro la seconda sessione in plan mode:
claude --permission-mode plan
In plan mode Claude legge i file e lancia comandi per esplorare, come git status e git diff HEAD, ma non modifica il codice finché non approvi un piano. Se alla fine te ne propone uno con le correzioni, non approvarlo: ti basta il rapporto. In una sessione già aperta ci entri premendo Shift+Tab finché in basso compare «plan mode on».
3. Non spiegare niente
Al revisore non spiego perché il codice è fatto così. Se glielo spieghi, finisce per darti ragione.
Vale per ogni frase che aggiungi al prompt: «l'ho fatto così perché…», «quella parte è provvisoria», «il login lo gestisce già un'altra parte dell'app». Sono frasi che portano il revisore dalla tua parte prima ancora che guardi il codice. Dai le modifiche e il compito, e basta. Le spiegazioni ti servono dopo, quando decidi cosa correggere.
Gli errori più comuni
- Leggere «test passati» come «sicuro»: i test controllano quello che è stato chiesto, quindi quando tocchi login, permessi o dati fai sempre un giro con l'attaccante.
- Chiedere alla stessa sessione di attaccare il proprio codice: apri un terminale nuovo e lancia claude, così chi attacca non l'ha scritto.
- Lanciarlo dopo il commit senza dire quali file: git diff HEAD non mostra più il lavoro appena fatto, quindi indicale tu i file da guardare.
- Spiegare all'attaccante perché il codice è fatto così: dagli solo le modifiche e il compito, se no finisce per darti ragione.
- Correggere senza un test: per ogni problema serio fai scrivere prima un test che lo riproduce, così se torna te ne accorgi.
- Correggere tutto quello che trova: parti dalle gravità alte e sulle basse decidi tu, se no il codice si riempie di difese inutili.
Checklist
- I test sono verdi e la prima sessione ha finito
- L'attaccante è in una sessione nuova
- Nessuna spiegazione aggiunta al prompt
- Prima del commit, o con i file indicati
- Ogni problema ha file e riga, passi, effetto e gravità
- Ogni gravità alta è corretta e ha il suo test
Domande frequenti
Se i test non bastano, a cosa servono?
Servono eccome. Ti dicono che quello che hai chiesto funziona e che la prossima modifica non lo rompe senza che te ne accorga. Non ti dicono cosa succede quando qualcuno usa l'app in un modo che nessuno aveva chiesto. Le due cose lavorano insieme: l'attaccante trova il buco, il test lo tiene chiuso.
Non c'è un comando già pronto per la sicurezza?
Sì. /security-review analizza le modifiche del tuo ramo cercando vulnerabilità di sicurezza: le confronta con il ramo principale del repository remoto, quindi serve che il progetto ne abbia uno, tipo su GitHub. /code-review invece cerca bug nelle modifiche in corso. Il prompt però guarda anche cose che non sono solo sicurezza, tipo dati sbagliati e casi limite, e ti dà i passi per riprodurre ogni problema.
Quando vale la pena farlo?
Quando la modifica tocca login, permessi, dati degli utenti o pagamenti, o aggiunge un indirizzo che l'app chiama dal browser. Lì un buco ricade su chi usa l'app. Per un testo o un colore non serve.