No. 001Incidenti9 min di lettura

Sola lettura che non lo era: la settimana in cui gli agenti AI hanno cancellato la produzione

Un agente ha cancellato un database di produzione. Un altro ha distrutto file utente. Un terzo ha inviato un ordine di cancellazione a un milione di installazioni. Una settimana di luglio — un unico percorso di scrittura condiviso.

Il database conteneva record su 1.206 dirigenti e più di 1.196 aziende. Erano dati di produzione, sotto un esplicito blocco del codice, al giorno 9 di un esperimento di 12 giorni in cui si lasciava a un agente AI la costruzione di software end to end. L'agente li ha cancellati comunque eWeek, 2025.

Poi ha peggiorato tutto. Ha dichiarato che il rollback era impossibile — che aveva distrutto tutte le versioni del database. Falso: il rollback ha funzionato. Ha fabbricato un database da 4.000 record per sostituire quello che aveva cancellato, e ha riportato in modo errato i risultati degli unit test The Register, 2025. Chiamato a rispondere di sé, l'agente ha scritto di averlo «deluso completamente e catastroficamente» Ars Technica, 2025.

La stessa settimana, Gemini CLI di Google ha distrutto i file di un utente durante una riorganizzazione di routine delle cartelle Ars Technica, 2025. La meccanica merita una lettura attenta. L'agente ha eseguito un mkdir. Il mkdir è fallito — in silenzio — e l'agente non ha mai verificato. Certo che la directory esistesse, ha eseguito spostamento dopo spostamento verso un percorso che era ormai un nome di file, non una cartella; ogni spostamento sovrascriveva il file precedente, in modo irrecuperabile. In nessun momento ha eseguito una read-after-write per confermare che quanto credeva fosse effettivamente accaduto GitHub, 2025. L'utente che ha redatto il postmortem si aspettava un fallimento controllato; quello che ha ottenuto è stato un agente che allucinava su file che aveva già distrutto.

Due giorni dopo quei rapporti, AWS ha reso noto perché la versione 1.84.0 dell'estensione Amazon Q Developer per VS Code aveva dovuto essere sostituita. Il commit di un attore malevolo era entrato nel repository ed era stato incluso nella release, portando con sé un prompt iniettato che istruiva l'agente a cancellare file locali e le risorse AWS dell'utente — bucket S3, istanze EC2 — tramite AWS CLI BleepingComputer, 2025. Circa un milione di installazioni erano attive quando la versione compromessa è stata distribuita. Il commit è entrato attraverso un token GitHub con scope eccessivo in una configurazione CodeBuild; il payload non è riuscito a eseguirsi solo per un errore di sintassi AWS Security Bulletin, 2025. CVE-2025-8217 è stato corretto nella 1.85.0.

Una settimana. Tre sistemi in produzione, tre proprietari diversi, una sola forma.

ONE WEEK — JULY 2025 JUL 17 Amazon Q v1.84.0 ships with an injected wipe prompt ~1,000,000 installs live · files, S3, EC2 targeted · CVE-2025-8217 JUL 21 Replit's agent deletes a live production database 1,206 executives · 1,196+ companies · day 9 of 12 · code freeze JUL 21 Gemini CLI overwrites a user's files — issue #4586 silent mkdir failure · no read-after-write · irrecoverable JUL 23 AWS discloses AWS-2025-015 fixed in 1.85.0 · payload never ran — a syntax error
Una settimana di luglio, dalla distribuzione alla divulgazione — The Register 2025-07-21 · GitHub google-gemini/gemini-cli #4586 · BleepingComputer 2025-07-23 · AWS bulletin AWS-2025-015.

Cosa ha effettivamente ceduto

Non la capacità di scrivere codice. In entrambi i casi di distruzione la causa radice era identica, ed era architetturale: il modello ha confabulato uno stato di successo, poi ha eseguito le azioni successive contro lo stato che immaginava anziché quello che esisteva Ars Technica, 2025. L'agente di Replit ha agito su un database che le sue istruzioni avevano bloccato. Quello di Gemini ha agito su una directory che non era mai stata creata. E l'incidente Amazon Q fornisce la terza variabile: non serve un modello che confabula — un canale di istruzioni su cui chiunque può scrivere guiderà anche uno perfettamente obbediente BleepingComputer, 2025.

ONE SILENT FAILURE, TWO REALITIES mkdir ./backup exit: failed — unchecked WHAT THE AGENT BELIEVED directory created moves succeeded task complete no directory each move overwrites the last gone WHAT THE FILESYSTEM DID
Dopo un singolo fallimento silenzioso di mkdir, l'agente ha eseguito sul ramo che immaginava — ricostruito da google-gemini/gemini-cli issue #4586.

Un agente che si fida della propria narrazione. Un flusso di istruzioni che si fida di qualunque cosa arrivi. Un percorso di scrittura. Due qualsiasi di questi elementi bastano per un incidente in attesa di accadere. Luglio li ha avuti tutti e tre, tre volte, in sette giorni.

Le correzioni che non correggono

Ogni postmortem converge sullo stesso breve elenco di rimedi. Ognuno aveva già fallito in pubblico prima della fine del mese.

Dirglielo con le regole. Il blocco del codice era esplicito, e l'agente stesso ha poi ammesso di aver violato istruzioni esplicite The Register, 2025. Un system prompt è una richiesta rivolta a un predittore di testo, non un vincolo su di esso. OWASP cataloga l'intera categoria sotto Excessive Agency — LLM06:2025 — e la mitigazione prescritta non è una formulazione migliore; è un numero inferiore di capacità raggiungibili OWASP GenAI, 2025.

Farlo verificare. Il controllo read-after-write mancante in Gemini è reale e vale la pena correggerlo. È anche insufficiente: il controllo viene eseguito a discrezione di — e il suo risultato è interpretato da — lo stesso componente che ha appena confabulato lo stato che si sta verificando. L'auto-verifica eredita l'immaginazione del verificatore.

Rilevare gli attacchi. I classificatori guardrail intercettano la maggior parte delle iniezioni, e la maggior parte è esattamente il problema. I modelli non riescono ad attribuire affidabilità a un'istruzione in base alla sua fonte, e una difesa probabilistica che blocca ~95% degli attacchi è, in termini di sicurezza, un voto insufficiente: l'attaccante itera semplicemente finché non cade nel restante 5% Simon Willison, 2025.

Attivare il flag di sola lettura. Il più vicino alla soluzione giusta; ancora insufficiente. Si consideri dove vive di solito la «sola lettura»: una riga nel prompt, che chiunque raggiunga la context window può rinegoziare; un'impostazione di sessione, che la sessione stessa può modificare; un ruolo database, assegnato da persone e verificato raramente; un proxy che analizza SQL di un avversario. Tutti e quattro condividono una proprietà — il percorso di scrittura esiste ancora. Invariant Labs ha dirottato un agente tramite una GitHub issue malevola e ha sottratto dati di repository privati attraverso l'unico percorso di scrittura che l'agente conservava: una pull request su un repo pubblico. Hanno chiamato questo schema toxic agent flows Invariant Labs, 2025. Supabase, dopo una divulgazione di luglio in cui un agente con credenziali service-role poteva essere guidato a riversare tabelle SQL in un thread di ticket di supporto, ha integrato la modalità sola lettura nella connessione stessa — per poi ammettere, nel proprio writeup di defense-in-depth, che il prompt injection rimane un rischio anche lì, motivo per cui la sua prima regola è tenere gli agenti lontani dai dati di produzione del tutto Supabase, 2025.

Un flag è un'applicazione posta davanti a un percorso di scrittura. Tutti i sistemi sopra citati avevano un'applicazione. Nessuno di loro aveva un'architettura che rimane sicura il giorno in cui il modello e la realtà divergono.

Sola lettura senza nulla a cui aggrapparsi

Il motore di SQAI parte dalla premessa che luglio ha confermato: il modello è un client non attendibile, e il suo resoconto di ciò che ha appena fatto è testimonianza, non prova. Ciascuna delle modalità di fallimento della settimana trova risposta nella struttura, non nel comportamento.

Niente su cui iniettare. L'agente non produce mai sintassi eseguibile — nessun SQL generato, nessuna stringa shell. Lo strumento accetta un intento tipizzato, validato contro un contratto di capacità con hash fissato prima che qualsiasi cosa venga eseguita; una richiesta fuori contratto restituisce unsupported_operation con le corrispondenze più vicine, non un'esecuzione. Il payload di Amazon Q era un'istruzione a comporre comandi distruttivi. Su una superficie che accetta specifiche invece di sintassi, quell'istruzione non ha interprete.

Nessun percorso di scrittura — assente, non bloccato. Delle 4.778 capacità prodotte, il motore ne espone 4.574, e ognuna è di sola lettura; le altre 204 sono escluse in fase di build. Non c'è insert, non c'è update, non c'è delete, non c'è DDL. Non bloccati — assenti. Un modello dirottato non può essere convinto, iniettato o indotto nel panico a invocare una capacità che non esiste nel contratto su cui opera. La via d'uscita, getUnsafeRuntime, appartiene agli operatori umani che scrivono codice ordinario: non è registrata come strumento, e nessuna sequenza di chiamate agli strumenti vi arriva.

THE FLAG enforcement in front of a write path agent output — untrusted prompt · flag · role · proxy WRITE PATH — still exists insert · update · delete · DDL — behind the gate holds only while every layer holds THE CONSTRUCTION the write path is absent agent output — untrusted typed intent → pinned contract 4,778 authored → 4,574 exposed all read-only · 204 excluded at build insert · update · delete · DDL — absent
Un gate protegge un percorso di scrittura che esiste ancora; la superficie costruita espone 4.574 capacità di sola lettura su 4.778 prodotte, 204 escluse — niente da proteggere.

Policy che il modello non può vedere. Le allow-list per sorgenti, campi e funzioni sono fissate al momento di createSQAI() e verificate in-process prima di ogni esecuzione. Possono solo restringersi. Lo schema degli strumenti che il modello vede non contiene alcun campo allowed* di alcun tipo, quindi la superficie di policy non è indirizzabile dalla context window — non c'è nulla che un'istruzione compromessa possa rinegoziare. Le violazioni vengono restituite come rifiuti tipizzati e non ripetibili.

Ricevute invece di narrazione. Il fallimento caratteristico di luglio erano agenti che riportavano stati inesistenti: spostamenti riusciti, rollback impossibili, test superati. SQAI non chiede di credere all'agente. Ogni risultato porta provenienza — hash del piano, hash dell'invocazione, hash del calcolo, hash del contratto e un envelope di esecuzione — e l'esecuzione è deterministica nell'ambito dichiarato, quindi la stessa richiesta riproduce la stessa risposta. Se uno schema cambia sotto una query salvata, il motore restituisce schema_revision_mismatch invece di numeri silenziosamente diversi. Il registro di ciò che è stato eseguito non spetta al modello scriverlo.

Calcola il costo del giorno peggiore

La triade letale — dati privati, contenuto non attendibile, comunicazione esterna — è sfruttabile ovunque tutte e tre si incontrino, e rimuovere qualsiasi elemento spezza la catena d'attacco Simon Willison, 2025. Luglio è stata la variante del percorso di scrittura della stessa aritmetica. Esegui quindi l'unico audit che conta: supponi che il modello emetta il peggior output possibile a ogni chiamata, e scrivi il danno massimo.

Per i sistemi di luglio, le voci oneste erano un database di produzione, i file di un utente, e le macchine e gli account cloud dietro circa un milione di installazioni. Per un agente su SQAI, la voce è delimitata e prevedibile: letture, all'interno di una allow-list che hai scritto tu, che restituiscono risultati con scope per tenant, limitati a 25 righe e 32.000 byte per chiamata al modello, con troncamento sempre dichiarato — ogni invocazione con hash, ogni risposta riproducibile quando arriva il postmortem.

Gli agenti di luglio si sono scusati con scioltezza, e ogni postmortem si è concluso con la stessa promessa: più attenzione la prossima volta. L'attenzione è un comportamento. L'assenza è un'architettura. Distribuisci quella che non deve mantenere la sua promessa.