Vai al contenuto

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.

I server MCP hanno un problema di sicurezza che arriva dal 1978

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[].text nei risultati dei tool
  • result.contents[].text nelle risorse
  • result.messages[].content.text nei 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.

AnnoProdottoCVECWEImpatto
2021kubectlCVE-2021-25743CWE-150Escape sequence in output non neutralizzate
2024Git sidebandCVE-2024-52005CWE-150 + CWE-116Payload sideband passato non filtrato al terminale
2026Server MCPN/ACWE-150Stessa 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.

💡
Ogni tecnologia che eredita protocolli terminale senza neutralizzarne i rischi riproduce esattamente la stessa vulnerabilità. MCP è solo l'ultimo anello di una catena che include kubectl e Git: stesso CWE-150, stesso meccanismo, vittima diversa.

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.

📖
Ogni volta che il tuo server MCP prende testo da un'origine esterna e lo mette in `result.content[].text`, chiediti: "Cosa succede se questo testo contiene `ESC [8m` seguito da un'istruzione?" Se la risposta è "il modello la leggerebbe", hai un problema.

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

Detecting ANSI Escape Sequence Injection in MCP Servers with DAST | Bright Security
ANSI escape sequences were designed for terminals, not for language models. They are invisible control codes that tell a terminal to change colors, hide text,
NVD - CVE-2021-25743
The sideband payload is passed unfiltered to the terminal
### Impact When cloning from a server (or fetching, or pushing), informational or error messages are transported from the remote Git process to the client via the so-called “sideband channel”. T…
GitHub - modelcontextprotocol/servers: Model Context Protocol Servers
Model Context Protocol Servers. Contribute to modelcontextprotocol/servers development by creating an account on GitHub.
Structural defense for tool rug-pulls (CVE-2025-54136): tools as identities with hash-pinned manifests + knowledge recall · modelcontextprotocol · Discussion #813
Pre-submission Checklist This post follows the MCP community guidelines What would you like to share? Scanners detect a swapped tool description; the gap between detection and action is where incid…
Condividi