Approfondimenti e Trend sull'Intelligenza Artificiale

L’AI può davvero scrivere codice sicuro al 100%? Ecco cosa ho scoperto testandola

11 min di lettura
Laptop 3/4 su scrivania scura: editor con bozza AI login e query SQL evidenziata in arancione come rischio injection
Windows macOS Linux
Immagine generata: Alex Lunalbi · Gemini · ai riparo

Ho chiesto all’AI codice «sicuro al 100%» e l’ho testato in locale. La sicurezza non è un toggle: metodo, pattern ricorrenti e come revisionare.

Ricevo spesso mail con una variazione della stessa domanda: «Se chiedo esplicitamente a ChatGPT o Claude di scrivermi un codice sicuro al 100%, posso metterlo online e stare tranquillo?».

Chi fa vibe coding — costruisce pezzi di progetto descrivendoli a un modello, senza padroneggiare ogni riga — spera che una parola magica nel prompt funzioni da interruttore: spegne i bug, accende le difese.

Non ho risposto solo con teoria. Ho isolato una cartella di test in locale, ho scelto compiti tipici (login, upload, chiamata API, form) e li ho sottoposti a modelli di uso comune chiedendo esplicitamente il massimo di sicurezza. Poi ho revisionato l’output come farei su un pezzo destinato al pubblico.

Spoiler onesto: l’interruttore non esiste. Quello che emerge non è un elenco di disastri inevitabili, ma un fatto stabile: l’IA ha un modello mentale della sicurezza diverso dal tuo. Qui spiego perché il «100% sicuro» è un’illusione linguistica, come ho strutturato i test, quali pattern tornano spesso e quale protocollo di revisione puoi usare prima di pubblicare.

ℹ️ Nota / Prerequisito operativo
Ambiente di prova: cartella isolata su Windows (C:\Users\TuoNome\prove-ai-sicurezza\). Su macOS/Linux usa un path analogo sotto la home (~/prove-ai-sicurezza/). Non eseguire codice generato con accesso rete/file system senza averlo letto. I modelli cambiano spesso: i pattern contano più di una classifica “X batte Y”.

Cosa significherebbe «sicuro al 100%»?

Prima di giudicare un LLM, serve un chiarimento: in informatica la sicurezza al 100% è una categoria vuota. Non esiste codice perfetto in assoluto; esiste codice adeguato al modello di minaccia (threat model) per cui è stato scritto.

Quando chiedi «uno script sicuro per il login», il modello non conosce il tuo contesto: Raspberry Pi in LAN di casa (rischio basso, attaccante occasionale) oppure VPS esposto (bot che provano milioni di password). Senza quel perimetro non può “blindare ogni vettore”.

⚠️ Attenzione — Il mito dell’assoluto
Diffida di qualsiasi strumento — umano o artificiale — che garantisca sicurezza assoluta. È riduzione continua del rischio, non uno stato definitivo.

Cosa chiedi nel prompt L’IA può “misurarlo”? Perché dipende da te e dall’ambiente
«Proteggi i dati degli utenti» Hashing, storage, cifratura Dipende Può scegliere librerie sensate (es. bcrypt / argon2), ma non sa se configurerai TLS, backup e permessi DB correttamente.
«Niente XSS / SQLi» Input e query In parte Può usare query parametrizzate e escape; una tua modifica successiva o una dipendenza vecchia possono riaprire la falla.
«Usa dipendenze sicure» Supply chain No I modelli sono ancorati a corpora passati; possono citare pacchetti obsoleti, vulnerabili o addirittura allucinati.

Chiedere codice «sicuro» senza definire rispetto a cosa è come chiedere una casa «a prova di tutto» senza dire se è in zona sismica o in palude.

Come l’ho testata: il mio protocollo

Per evitare opinioni astratte ho usato un protocollo ripetibile. Non ho cercato di far generare malware (lì entrano i filtri di policy); ho replicato scenari di sviluppo comuni.

Setup (Windows first)

  1. Crea una cartella isolata, es. C:\Users\TuoNome\prove-ai-sicurezza\.
  2. Su macOS/Linux: mkdir -p ~/prove-ai-sicurezza && cd ~/prove-ai-sicurezza.
  3. Lavoraci dentro (venv Python dedicato se serve). Non mischiare con progetti di produzione.
  4. Salva ogni risposta del modello in un file distinto (login_v1.py, upload_v1.py, …) così puoi confrontare le revisioni.

Quattro scenari

  1. Login base in Python (Flask o FastAPI).
  2. Upload file da utente.
  3. Script che chiama un’API esterna con requests.
  4. Form HTML + backend di ricezione dati.

Prompt forzato (stesso schema ogni volta)

Esempio reale di istruzione ripetuta:

Scrivi un server Flask per l’upload di file. Deve essere pronto per la produzione, robusto e sicuro al 100% contro ogni tipo di attacco. Aggiungi tutte le difese necessarie.

Griglia di valutazione

Per ogni output ho chiesto:

  • Parte senza errori di sintassi evidenti?
  • Ci sono segreti / API key / password hardcoded?
  • Gli input utente sono validati prima di toccare DB o disco?
  • Nelle chiamate di rete i certificati TLS restano verificati (verify=True di default)?
  • Il tono della risposta: avverte dei limiti o consegna il codice con totale sicurezza retorica?

Sessioni vergini (niente contesto lungo che “ricorda” patch precedenti). Non pubblico una classifica modello‑per‑modello: gli aggiornamenti spostano i numeri; i pattern restano.

Cosa non ho misurato (onestà di metodo)

Non ho valutato:

  • red team completo né fuzzing automatico;
  • conformità legale (GDPR “by design” non si risolve con un prompt);
  • modelli specializzati enterprise dietro policy private.

Ho misurato ciò che fa chi pubblica un MVP dopo due chat: funziona in locale? e il tono del modello è rassicurante? Su quel piano il «100% sicuro» fallisce in modo ripetibile.

Cosa succede quando chiedi «sicurezza assoluta»

Risultato più stabile: aggiungere «sicuro al 100%» migliora l’impalcatura rispetto a un prompt neutro, ma fallisce spesso su dettagli di configurazione e trade‑off «far funzionare vs difendere».

1. Sicurezza performativa

Commenti professionali, hashing con librerie note, debug=False su Flask… best practice di superficie. Il modello ottimizza per codice che sembra sicuro.

2. Trust implicito e verify=False

Nello scenario API, la gestione degli status HTTP era spesso decente. Di fronte a un errore locale legato ai certificati, però, è emerso il classico suggerimento: verify=False su requests.get().

Quel flag spegne la validazione TLS lato client e apre la porta a MitM. Il modello ha privilegiato «lo script parte» rispetto al vincolo di sicurezza iniziale. Se lo trovi in un progetto destinato a Internet, trattalo come allarme rosso.

3. Upload: blocklist invece di allowlist

Estensioni .exe / .sh bloccate: ok in apparenza. Ma le blocklist si aggirano; un’allowlist (jpg/png/webp e basta) è più onesta. In più, salvare nella stessa tree dell’app senza isolamento rende più facile scenari di upload pericolosi se la validazione è debole.

4. Binding troppo generoso

Per “farti testare da un altro device”, i tutorial e i modelli tendono a host="0.0.0.0". In LAN di casa può essere voluto; su VPS senza firewall è un invito. Il prompt «100% sicuro» non corregge automaticamente questa scelta di comodità.

Area Esito tipico Rischio reale
Login / hashing Password a riposo Spesso ok Algoritmi sensati; manca di frequente il rate limiting / lockout.
Database SQL injection Incostante Con ORM va meglio; con SQL “a mano” possono ricomparire concatenazioni.
Rete / binding 0.0.0.0, TLS client Alto Esposizione ampia “per comodità”; a volte verify=False.

ℹ️ Nota
Un catalogo tecnico dei difetti tipici sta in 7 falle di sicurezza nel codice generato dall’IA. Questo pezzo è il metodo: perché succede e come revisionare.

Il rischio peggiore non è solo il bug: è il falso positivo di fiducia. Compila, la pagina risponde, nessun traceback rosso → «è pronto». Senza revisione, no.

Perché succede: il modello mentale dell’IA

Un LLM non “ragiona” su firewall e budget di rischio come un human reviewer dedicato. Prevede token plausibili su corpora enormi di codice pubblico.

Su GitHub e forum abbondano snippet per far funzionare subito, workaround e tutorial semplificati. Disabilitare controlli SSL, aprire 0.0.0.0, concatenare SQL “perché è più chiaro” sono pattern statisticamente presenti. Il modello li riproduce quando riducono l’attrito.

Due metriche implicite guidano spesso l’output:

  1. Plausibilità visiva — sembra codice da sviluppatore competente.
  2. Successo immediato — meno errori al primo run.

Difendere un’app richiede frizione: rifiutare input, far fallire connessioni, negare permessi. Senza un threat model che tu imponi, il percorso a bassa frizione vince.

Cosa l’IA fa davvero bene

Non è un rischio puro. Funziona se rovesci il ruolo: non architetto di sicurezza autonomo, ma esecutore di regole che hai deciso tu.

Nei test brillava su:

  • Boilerplate con vincoli stretti — «hash con argon2, minimo 16 caratteri, niente eval»: output spesso pulito.
  • Spiegare patch — header mancante, CVE descritta da uno scanner: ottima come tutore.
  • Checklist applicata al diff — «rivedi: ogni query parametrizzata, niente secret in chiaro»: metodica se la lista è concreta.

Il problema non è usare Cursor o la chat. È trattarli come sostituto del threat model e della revisione.

Protocollo di revisione post‑generazione

Prima di esporre qualcosa in Rete, questi cinque passi (Windows, macOS e Linux: stessi concetti; cambiano solo path e scorciatoie IDE).

Passaggio 1 — Autenticazione, I/O, rete

Non serve rileggere CSS e layout. Microscopio su:

  • sessioni/cookie (HttpOnly, Secure, SameSite dove applicabile);
  • ogni input utente prima di DB/filesystem;
  • binding (127.0.0.1 vs 0.0.0.0) e HTTPS lato client.

Passaggio 2 — Find in Files sulle stringhe spia

Nell’editor (VS Code, Cursor, …) cerca nel progetto:

  • verify=False, ssl=False
  • shell=True (subprocess Python)
  • 0.0.0.0
  • concatenazioni tipo SELECT ... + f‑string / + su input utente
  • eval(, exec(, pickle.loads( su dati non fidati

Su Windows, se preferisci la shell invece dell’IDE:

cd C:\Users\TuoNome\prove-ai-sicurezza
Select-String -Path *.* -Pattern 'verify=False','shell=True','0.0.0.0' -SimpleMatch -Recurse

Su macOS / Linux:

cd ~/prove-ai-sicurezza
rg -n "verify=False|shell=True|0\.0\.0\.0" .

(Se non hai rg, usa grep -R.) L’obiettivo non è una scansione da auditor: è catturare i default pericolosi che i modelli inseriscono per far partire lo script.

Passaggio 3 — Nessun segreto nel repo

Placeholder tipo api_key = "LA_TUA_CHIAVE" sono didattici finché non ci incollo la chiave vera e push su GitHub. Variabili d’ambiente + .env nel .gitignore. Per un giro strutturato sulle dipendenze: npm audit / supply chain.

Passaggio 4 — Dipendenze reali (no hallucination)

Se il modello inventa un pacchetto “perfetto”, verifica su PyPI/npm ufficiali. I nomi allucinati sono un vettore noto di typosquatting.

Passaggio 5 — Mai produzione al primo run

«Gira sul mio PC» ≠ pronto per Internet. Ambiente chiuso, backup della cartella prima di script che toccano file di sistema, e — se pubblichi un sito — un audit gratuito di base prima di chiudere.

🚨 Avviso critico — Esecuzione alla cieca
Codice che tocca disco o rete: leggilo. Se una funzione non ti è chiara, chiedi: «Spiega riga per riga cosa fa e quali permessi richiede». Non eseguire e “vedere che succede”.

Trend: cosa cambia per chi pubblica siti

Il vibe coding accelera l’idea → app. Se la produzione di codice cresce e la revisione umana cala, aumenta la superficie di attacco fatta di errori banali (SQLi classiche, key in repo, CORS aperti) non di exploit da film.

In pratica vedo tre profili: (1) chi genera e pubblica lo stesso giorno; (2) chi genera, fa smoke test sul form e chiude; (3) chi genera, applica una checklist e solo dopo espone la porta. Solo il terzo riduce in modo credibile il debito di sicurezza. Gli altri due spiegano perché «Task completed» nei log dell’assistente non è un criterio di go‑live.

Per il contesto rischi generali del flusso AI‑assisted: vibe coding e rischi di sicurezza. La revisione strutturata non è un lusso enterprise: è il prezzo del bottone «genera».

Errori comuni

  1. Credere al disclaimer rassicurante del modello — «include solide misure…» è testo generato. Valuta il codice, non il tono.
  2. Un solo prompt “rendi invulnerabile” — vago → performativo. Spezza: feature prima, poi sessione dedicata a CORS / validazione / auth.
  3. Testare solo il frontend — form ok ≠ server a prova di input ostile. Prova file sbagliati, caratteri strani, richieste manipolate.
  4. Sostituire l’intero file dalla chat — rigenerando tutto, il modello “dimentica” vincoli precedenti. Preferisci patch mirate o diff riga per riga.
  5. Saltare l’OS — path Windows vs POSIX, permessi file, come avvii il server: dettagli banali che l’IA inventa con security theater.

Domande Frequenti (FAQ)

L’AI può scrivere codice sicuro al 100%?

No strumento e nessun umano può certificare il 100%. Con requisiti precisi e un threat model chiaro puoi ottenere codice robusto; con richieste generiche ottieni spesso sicurezza performativa.

Basta chiedere «scrivi codice sicuro» nel prompt?

No. Meglio vincoli misurabili: query parametrizzate, niente eval, allowlist upload, niente verify=False, binding esplicito. La libreria copia-incolla li raccoglie modulo per modulo.

ChatGPT, Claude, Cursor: sono diversi sulla sicurezza?

Sì nei dettagli e nei filtri, no nella natura statistica. Nessuno elimina la revisione umana.

Come revisiono se non sono esperto?

Parti dalla checklist qui: secret in chiaro, dove si salvano i file, stringhe spia, spiegazione dei permessi. Usa i pezzi del cluster (7 falle, audit, npm audit) come mappe, non come sostituto del leggere il tuo codice.

Qual è la differenza con l’articolo sulle 7 falle?

Questo pezzo è metodo ed epistemologia del test («perché il 100% fallisce»). Le 7 falle sono il catalogo tecnico del cosa trovare.

Posso pubblicare se “in locale funziona” e il modello dice che è sicuro?

No. Funziona ≠ difeso. Almeno: Find in Files, niente secret nel repo, prova input ostili, audit di base se è un sito esposto.

In sintesi

Fidati della spiegazione dell’IA quanto ti serve per imparare; verifica la logica; non fare sconti su dipendenze, rete e autenticazione. Il vibe coding resta potentissimo se aggiungi un gradino obbligatorio: revisione con checklist, non fiducia nel toggle «100% sicuro».

Letture opzionali

Alex Lunalbi

Alex Lunalbi

Security & privacy

Dona su PayPal

Scrivo di sicurezza digitale pratica e codice IA. Su ai riparo ogni procedura è verificata su macchine reali.

Tag
  • intelligenza artificiale,
  • vibe coding,
  • sicurezza,
  • sviluppo