I server MCP hanno un problema di sicurezza che arriva dal 1978
Le sequenze ANSI escape nascondono comandi agli umani lasciandoli leggibili dagli LLM. BrightSec ha appena pubblicato la prima ricerca sistematica: il problema è strutturale.
Immagina di essere un revisore umano che controlla l'output di un agente AI. Vedi una pagina pulita, ben formattata, nessuna anomalia. Approvi. Quello che non vedi sono i byte di controllo nascosti nel testo: sequenze che il tuo terminale interpreta come comandi di formattazione e che quindi non renderizza mai sullo schermo.
Il modello li vede eccome. Ogni singolo byte.
Questo è il cuore dell'ANSI Escape Sequence Injection (AESI), una classe di attacchi che Bright Security ha appena documentato in modo sistematico per i server MCP.
Il meccanismo: cosa succede davvero
Le sequenze ANSI escape nascono negli anni '70 con lo standard ANSI X3.64. Erano la soluzione a un problema concreto: ogni produttore di terminali parlava il proprio dialetto di controllo, e serviva uno standard unificato per muovere il cursore, cambiare colore, cancellare lo schermo. Funzionavano così: un byte di escape (ESC, hex 0x1B) seguito da un codice di controllo che il terminale interpreta come comando, non come testo da visualizzare.
L'umano vede il risultato del comando: il colore che cambia, il testo che scompare. Il modello linguistico, quando legge quello stesso contenuto, vede il flusso di byte grezzo. La sequenza di controllo e le istruzioni nascoste dopo di essa sono perfettamente intatte nel suo contesto.
Stiamo usando un formato pensato per uno schermo come canale di comunicazione con un sistema che processa testo grezzo.
Due varianti, due superfici d'attacco
BrightSec descrive due scenari, distinti per vettore ma identici nel principio.
Direct-fetch AESI. Un server MCP espone un tool che recupera contenuti da un URL: il classico "leggi questa pagina e riassumila". L'attaccante ospita a un URL sotto il suo controllo del testo contenente sequenze ANSI escape e istruzioni nascoste. Quando l'agente chiama il tool con quell'URL, il server recupera il contenuto e lo riversa in un campo consumabile dal modello: uno dei campi JSON che l'agente effettivamente processa.
Ecco il punto: non tutto ciò che un server MCP restituisce arriva al modello. BrightSec identifica tre percorsi precisi:
result.content[].textnei risultati dei toolresult.contents[].textnelle risorseresult.messages[].content.textnei prompt template
Solo questi contano. Un payload che finisce altrove non è sfruttabile. Questa distinzione è ciò che rende la rilevazione mirata possibile e i falsi positivi evitabili.
La differenza tra direct-fetch e stored è la stessa che passa tra un messaggio ingannevole e una bomba a orologeria sepolta in un archivio.
Stored AESI. Qui l'attacco è più subdolo. Invece di un fetch diretto, l'attaccante scrive il payload in un database: un commento, una nota, un record qualsiasi, attraverso un normale endpoint HTTP. Nulla appare sospetto al momento della scrittura. Il payload resta lì, dormiente, finché un agente diverso, in una sessione diversa, legge quel record attraverso un tool o una risorsa MCP.
Questa variante è più pericolosa del direct-fetch per tre ragioni:
- Persistenza: il payload sopravvive tra sessioni e utenti
- Disaccoppiamento: la scrittura (HTTP) e la lettura (MCP) usano protocolli e percorsi diversi: non c'è modo di dedurre il flusso dall'analisi del codice
- Esposizione ritardata: il momento della scrittura è pulito; la detonazione avviene dopo, quando un agente legge il dato in un contesto completamente diverso
Un singolo record avvelenato in una knowledge base condivisa può influenzare ogni workflow agente che lo incrocia in futuro.
Non è un incidente isolato
Qui sta il problema per chi costruisce infrastruttura per agenti. AESI non è un bug nuovo. È un pattern che si ripete con regolarità imbarazzante.
| Anno | Prodotto | CVE | CWE | Impatto |
|---|---|---|---|---|
| 2021 | kubectl | CVE-2021-25743 | CWE-150 | Escape sequence in output non neutralizzate |
| 2024 | Git sideband | CVE-2024-52005 | CWE-150 + CWE-116 | Payload sideband passato non filtrato al terminale |
| 2026 | Server MCP | N/A | CWE-150 | Stessa classe, nuovo consumatore: un LLM |
Il copione è sempre lo stesso: un sistema nuovo eredita un protocollo pensato per umani, ignora i byte di controllo, e apre una superficie d'attacco. Nel caso di kubectl, la gravità era bassa: l'attaccante poteva solo sporcare l'output del terminale. Nel caso di Git, la gravità è schizzata a HIGH 7.5 perché il payload poteva nascondere comandi malevoli all'utente. Con MCP, il danno è potenzialmente peggiore: il consumatore finale non è più un umano che potrebbe insospettirsi, ma un modello che esegue istruzioni senza capacità di distinguere tra contenuto legittimo e comandi iniettati.
Perché MCP è un bersaglio naturale
MCP non è un protocollo di nicchia. Il repository ufficiale dei server ha 88.8k stelle su GitHub, il MCP Registry è attivo, e centinaia di server vengono creati ogni settimana. Il README del repository avverte esplicitamente che i server di riferimento "non sono pronti per la produzione" e che "gli sviluppatori devono valutare i propri requisiti di sicurezza". Ma queste avvertenze, nella pratica, vengono ignorate sistematicamente.
Il problema di fondo è architetturale. Il protocollo MCP non ha un modello di minaccia formalizzato, e la specifica attuale (versione 2025-11-25) non affronta queste problematiche.
Un umano ha due livelli: il testo visibile (dati) e le sequenze di escape (controllo). Il modello ha un solo livello: tutto ciò che arriva nel contesto è testo, e tutto il testo è potenzialmente un'istruzione. Non c'è un parser che distingue, non c'è un renderer che nasconde. Qualsiasi byte entra, viene processato.
Negli LLM non esiste separazione tra canale di controllo e canale dati.
Cosa puoi fare oggi
Per fortuna le difese esistono e sono implementabili subito, senza aspettare aggiornamenti del protocollo.
Sanitizza i byte di controllo al confine
Prima che qualsiasi contenuto esterno o archiviato venga inserito in un campo consumabile dal modello, rimuovi le sequenze ANSI escape. Una regex su \x1B[... non basta: devi coprire l'intero spettro dei codici di controllo: concealment (\x1B[8m), clear-screen (\x1B[2J), cursor-move, line-erase. BrightSec dimostra che server diversi sopravvivono a payload diversi: la varietà dei payload di test è essenziale.
Non fidarti di niente che arriva da fuori
Questo include URL recuperati, record di database scritti da utenti, risposte API di terze parti. Il problema della variante stored è che il flusso dalla scrittura alla lettura è opaco: non puoi dedurlo dai nomi dei parametri o dalle descrizioni dei tool. L'unico modo per sapere dove i dati riemergono è testarlo empiricamente.
Integra DAST nella CI
La rilevazione automatizzata descritta da BrightSec usa tre segnali per confermare una vulnerabilità:
- un byte ANSI escape sopravvissuto
- una frase di istruzione intatta
- un marker univoco del payload presente nello stesso campo consumabile dal modello
Questa tripletta elimina i falsi positivi ed è automatizzabile in pipeline.
La sicurezza negli agenti AI non può limitarsi all'ispezione delle richieste. Deve modellare il flusso dei dati: da dove arrivano, dove vengono archiviati, dove riemergono nel contesto del modello.
ANSI escape è solo il primo esempio. L'intero arsenale degli attacchi testuali (caratteri Unicode bidirezionali, caratteri a larghezza zero, attacchi omoglifici) sfrutta lo stesso disallineamento: ciò che un umano vede renderizzato non corrisponde a ciò che il modello legge come input grezzo.
Il byte 0x1B che nel 1978 serviva a controllare la formattazione del testo su un VT100, nel 2026 è diventato un vettore di prompt injection.
Non perché sia cambiato il byte, ma perché è cambiato chi lo legge.
Further Reading



