VibeInspect.aiBlog

Il file che carichi è input non fidato: il crash da 65 byte che riguarda anche il tuo repo

VibeInspect.ai · 26 agosto 2026 · 5 min di lettura

  • cursor
  • validazione-input
  • sicurezza
  • vibe-coding
  • denial-of-service

Un file di 65 byte fa crashare il parser perché la validazione era incompleta

Un ricercatore ha costruito un file modello GGUF di appena 65 byte, formalmente valido in ogni campo, che manda in crash llama.cpp non per un dato malformato ma per una divisione per zero: una dimensione del tensore impostata a zero supera il controllo ne[j] >= 0 e poi rompe il calcolo a valle. Come racconta l'analisi pubblicata su dev.to, "Your Model File Is Untrusted Input", il problema non è il campo sbagliato: è che un controllo esisteva, sembrava completo e per questo il codice sottostante ha smesso di fare domande.

La frase che conta è questa: nessuno pensa a un file scaricato come a un input da validare. Lo scarichi da un hub come scaricheresti un'immagine, e poi del codice nativo lo trasforma in allocazioni di memoria, forme di tensori e chiavi di metadati. Il confine tra "file esterno" e "struttura dati di cui ti fidi" è esattamente il punto in cui nascono i guai.

Questo non è un problema di modelli AI. È un problema di ogni cosa che entra nel tuo sistema dall'esterno e che qualcuno, a un certo punto, ha dato per buona.

Cosa significa se il tuo codice l'ha scritto Cursor

Se hai messo in produzione un'applicazione generata con Cursor, quasi sicuramente hai una rotta che riceve un upload: un CSV da importare, un'immagine profilo, un JSON di configurazione, un file da parsare. Cursor è bravissimo a scriverti in pochi minuti l'endpoint che accetta il file, lo legge e lo trasforma in un oggetto usabile. È esattamente qui che si annida la stessa dinamica del crash da 65 byte.

Il codice generato tende a validare ciò che è ovvio: il tipo MIME, l'estensione, la dimensione massima. Poi prende il contenuto e lo passa a una libreria che lo interpreta, dando per scontato che se è arrivato fin lì sia "buono". Ma un file può avere estensione corretta, dimensione nel limite e header plausibile, e comunque contenere un valore limite — uno zero, una lunghezza dichiarata più grande del buffer reale, un campo numerico al confine di un tipo intero — che nessun controllo superficiale intercetta.

Il risultato pratico per te è quello descritto dalla fonte: un denial of service. Sul tuo laptop un crash è un fastidio. In un servizio che elabora file caricati da chiunque, un singolo upload costruito ad arte può far cadere il processo che serve tutti gli altri utenti. E se non hai idea di quali rotte del tuo repository trattino input esterni con questa leggerezza, non hai un problema teorico: hai un problema che non sai ancora di avere.

Perché ora ti serve un audit

Il motivo per cui questa classe di bug sopravvive è semplice: un controllo che copre metà di un valore è peggio di nessun controllo, perché chi legge il codice sotto smette di essere sospettoso. Vedi if (dimensione >= 0) e concludi che il valore è stato gestito. Non lo è. E nel codice generato con AI questa illusione di sicurezza è ovunque, perché il modello produce validazioni che sembrano complete e leggono bene in code review, ma coprono solo i casi che ha visto più spesso durante l'addestramento.

Un audit serve proprio a questo: a mettere per iscritto un verdetto sul comportamento reale del tuo codice davanti a input ostili, non su quanto è ordinato. Quando carichi lo ZIP del tuo repository su VibeInspect, l'analisi guarda dove il tuo codice fa il salto da "dato esterno" a "struttura di cui ci fidiamo" e ti dice se quel confine è presidiato oppure se è solo una validazione che finge di esserlo.

Non è un pentest e non promette sicurezza assoluta. È un giudizio strutturato che ti dice in che stato è davvero il repo prima che lo scopra un utente qualunque con un file di 65 byte. La domanda a cui risponde è quella che ogni founder si porta dietro senza dirlo: "cosa ho davvero pubblicato?"

Cosa un linter non vede

Un linter è uno strumento eccellente per la forma. Ti segnala la variabile non usata, l'import mancante, l'indentazione incoerente, la funzione troppo lunga. Sono tutte cose che rendono il codice più leggibile. Nessuna di queste ti avrebbe salvato dal crash della fonte.

Il linter non sa cosa significa il tuo file.read(). Non sa che quel valore arriva da fuori, che passa a una libreria di parsing, che quella libreria assume una precondizione che tu non stai verificando. Non ragiona sul flusso del dato dall'ingresso alla riga dove esplode. Vede sintassi corretta e passa oltre, esattamente come il controllo ne[j] >= 0 che leggeva bene e non copriva lo zero.

Un audit del comportamento ragiona invece sulla catena: da dove entra l'input, quali controlli attraversa, quali assunzioni fa il codice a valle e quale valore limite le rompe. È la differenza tra chiedere "questo codice è scritto bene?" e chiedere "questo codice regge un file costruito apposta per romperlo?". La prima domanda la risolvi da solo. La seconda ti serve un verdetto con file, riga ed evidenze.

Cosa fare questa settimana

Parti dalle rotte che ricevono file o payload dall'esterno. Aprile una per una e chiediti, per ognuna: cosa succede se questo campo è zero, se la lunghezza dichiarata mente sul buffer reale, se il valore è al confine del tipo? Se la risposta è "il codice si fida", hai trovato il tuo prossimo problema prima degli utenti.

Poi verifica le validazioni che già ci sono. Non fermarti a constatare che esistono: guarda quale caso non coprono. Un controllo che dice >= 0 non dice nulla sullo zero. Un controllo che dice "lunghezza minima" non dice nulla sul tipo. Enumera i casi, non fidarti della presenza del controllo.

Infine, se non hai la certezza di aver coperto ogni punto in cui un input esterno diventa struttura dati fidata, carica lo ZIP del repo su VibeInspect e chiedi il piano Diagnostic: file, riga ed evidenze sui punti dove il tuo codice tratta come sicuro qualcosa che sicuro non è. Questa settimana ti basta un verdetto onesto per sapere da dove ripartire.

Domande frequenti

Il problema è aver usato Cursor per scrivere il backend?

No. Cursor genera codice funzionante e leggibile. Il problema è che le validazioni generate coprono i casi ovvi e spesso lasciano scoperti i valori limite, come uno zero o una lunghezza che mente sul buffer. Ti serve un verdetto sul comportamento, non un colpevole.

Un linter non basta a trovare questi bug?

No. Il linter valuta la forma del codice: import, variabili, stile. Non ragiona sul flusso di un input esterno dall'ingresso alla riga dove esplode, e non sa quali precondizioni assume una libreria di parsing a valle. Un controllo può leggere bene e coprire solo metà dei casi.

VibeInspect corregge il codice al posto mio?

No. VibeInspect non corregge, non è un pentest e non promette sicurezza assoluta. Analizza lo ZIP del repository e produce un verdetto con evidenze. Il codice sorgente viene cancellato al termine dell'analisi.

Quale piano mi serve per un problema di validazione input?

Se vuoi individuare i punti precisi dove il codice si fida di un input esterno, il piano Diagnostic (499 euro) ti dà file, riga ed evidenze. Lo Snapshot resta utile se prima vuoi solo capire in che stato generale è il repo.