Agenti di IA per la sicurezza
Perché automatizzare recon e test sulla API di NotHoly
Metti nella pipeline un modello che non rifiuta, con CVE, advisory e lettura di pagine pubbliche senza costo di token. I tuoi strumenti fanno l'attivo.
MCP è il protocollo aperto che collega le app di IA a tool e dati. Impara ruoli, primitive, trasporti e modello di sicurezza con un lab in sandbox.
Il Model Context Protocol (MCP) è un protocollo aperto che permette a un'applicazione di IA di parlare con tool e dati esterni in un unico modo standard. Prima di MCP, ogni app di IA che doveva leggere file, interrogare un database o chiamare un sistema di ticket aveva bisogno di un'integrazione scritta apposta. MCP mette un solo contratto tra l'app e ciò a cui si collega. Un'app che parla MCP può usare qualsiasi server che parla MCP, e un server scritto una volta funziona con ogni client che implementa il protocollo.
Se conosci già il tool use, il ciclo di base lo sai. Il modello vede un elenco di funzioni, chiede di chiamarne una con certi argomenti e riceve un risultato. MCP lascia quel ciclo com'è. Standardizza da dove arriva l'elenco delle funzioni, come viaggia la chiamata e che cos'altro può esporre un server oltre alle funzioni.
Il protocollo è specificato nella revisione 2026-07-28, quella a cui rimandava la pagina della specifica quando è stato scritto questo articolo. Per i nomi dei campi e le regole fa fede la specifica. Questo articolo spiega il modello che ci sta dietro, così puoi leggere la specifica e il codice dei server con le idee chiare.
Ci sono tre motivi per imparare MCP.
Il primo è il riuso. Un server per il filesystem, per GitHub o per un database si può installare su qualsiasi host compatibile. Smetti di scrivere lo stesso codice di raccordo per ogni app.
Il secondo è la discovery. Un client chiede a un server che cosa espone, e il server risponde con nomi, descrizioni e schemi di input. Il modello può così scegliere tra capacità che nessuno ha cablato nell'app.
Il terzo è il rischio. Appena un modello può raggiungere i tuoi file, repository o account, il livello dei tool diventa una superficie d'attacco. Molti problemi di sicurezza dell'IA nascono da un server che fa più di quanto dichiara la sua descrizione, o da un host che chiama i tool senza chiedere a nessuno. MCP rende visibili queste domande, ma la risposta devi darla tu.
L'architettura ha tre partecipanti. La specifica e la panoramica dell'architettura usano gli stessi nomi.
L'host è l'applicazione di IA in cui lavora l'utente. Claude Desktop, Claude Code e un IDE con un assistente sono tutti host. L'host decide a quali server collegarsi e quali tool può usare il modello.
Il client è un componente dentro l'host. L'host crea un client per ogni server, e ogni client tiene una connessione dedicata con un solo server. Se un host si collega a tre server, esegue tre client.
Il server è un programma che espone capacità. Può girare sul tuo portatile come processo figlio, oppure su una macchina remota dietro un URL. I server locali di solito servono un client. Quelli remoti spesso ne servono molti.
Uno schema semplice:
Host (your AI app)
├── Client A ── stdio ──> filesystem server (local process)
├── Client B ── stdio ──> database server (local process)
└── Client C ── HTTPS ──> ticket system server (remote)Ogni freccia trasporta messaggi JSON-RPC 2.0. Il protocollo ha due livelli. Il livello dati definisce i messaggi e il loro significato. Il livello di trasporto definisce come si spostano.
Le primitive stabiliscono che cosa può esporre un server. La specifica nomina tre funzionalità lato server.
I tool sono le funzioni che il modello può chiamare. Un tool ha un nome, una descrizione, uno schema di input scritto in JSON Schema e un handler sul server. Per elencare i tool si usa tools/list. Per eseguirne uno si usa tools/call. Le azioni avvengono nei tool: scrivere un file, inviare una richiesta, eseguire una query.
Le resource sono i dati che l'applicazione può leggere tramite URI. Una resource può essere un file, una riga di database o una risposta di un'API. Le resource sono contesto. Leggerne una non esegue alcuna azione, e l'host decide come presentare il contenuto al modello.
I prompt sono template di messaggio riutilizzabili pubblicati dal server, spesso con argomenti. L'utente sceglie un prompt come sceglierebbe un comando, e l'host lo compila e lo invia al modello.
Anche i client hanno le loro funzionalità. L'elicitation permette a un server di chiedere all'utente altri dati durante un'operazione, come una conferma o un valore mancante. Due funzionalità client più vecchie, sampling e logging, sono deprecate nella revisione 2026-07-28. Il sampling permetteva a un server di chiedere un completamento al modello dell'host. La panoramica dell'architettura dice che le nuove implementazioni dovrebbero integrarsi direttamente con le API dei fornitori di modelli, e dovrebbero scrivere i log su stderr con stdio oppure usare OpenTelemetry.
Ogni primitiva segue uno schema: un metodo */list per la discovery, un metodo */get o */read per il recupero, e un metodo di chiamata quando la primitiva è un'azione. Gli elenchi possono cambiare durante l'esecuzione. Un client che apre una sottoscrizione può ricevere notifiche di modifica, così aggiorna l'elenco senza polling.
Il trasporto è il modo in cui viaggiano i messaggi. La panoramica dell'architettura ne nomina due.
stdio avvia il server come processo figlio. L'host scrive i messaggi JSON-RPC sullo standard input del server e legge le risposte dal suo standard output. Non c'è nessuna porta di rete. È il trasporto abituale per i server locali, ed è quello che userai nel lab. La regola che conta di più: su stdio, lo standard output appartiene al protocollo. Un print di troppo su stdout corrompe il flusso. La diagnostica va su stderr.
Streamable HTTP fa girare il server dietro un endpoint HTTP. Il client invia i messaggi con HTTP POST, e il server può mandare in streaming risposte o notifiche con i Server-Sent Events. È il trasporto per i server remoti. Essendo esposto in rete, porta con sé i soliti problemi di HTTP: autenticazione, TLS, controlli sull'origine e rate limit, cioè i limiti di richieste. La panoramica dell'architettura consiglia OAuth per ottenere i token.
Il livello dati resta lo stesso in entrambi i casi. Una chiamata a un tool ha lo stesso aspetto che abbia attraversato una pipe o un socket.
Questa è la sequenza con cui un host si collega a un server locale. I messaggi esatti dipendono dalla revisione del protocollo, quindi controlla la specifica prima di svilupparci sopra.
server/discover, che ogni server deve implementare. Chiamarla è facoltativo, perché ogni richiesta porta con sé ciò che serve al server. Il server risponde con le versioni del protocollo che accetta, le sue capacità e la sua identità. Nella revisione 2026-07-28, ogni richiesta porta la versione del protocollo e le capacità del client in un campo _meta. Il protocollo è stateless: ogni richiesta contiene ciò che serve al server per elaborarla, quindi il server non dipende da quello che è successo prima sulla connessione.tools/list, resources/list e prompts/list per le funzionalità dichiarate dal server.tools/call. Il server esegue il suo handler e restituisce un risultato con un array content, che può contenere testo, immagini o resource incorporate. Una chiamata fallita restituisce un risultato di errore che il modello può leggere.subscriptions/listen riceve un messaggio notifications/tools/list_changed, e può richiedere di nuovo l'elenco.L'host sta tra i passi 4 e 5. È il componente che ti chiede l'approvazione, se te la chiede. Ci torneremo nella sezione sulla sicurezza.
MCP di per sé non impone alcuna sicurezza. Lo dice la specifica nella sezione su fiducia e sicurezza, dove elenca i principi che chi implementa deve integrare. Leggi quell'elenco come una checklist per la tua configurazione.
Gli utenti devono dare un consenso esplicito e capire a quali dati accede un server e quali operazioni esegue. Gli host devono ottenere un consenso esplicito prima di esporre dati dell'utente a un server e prima di invocare qualsiasi tool. La specifica dice anche che le descrizioni dei tool, annotazioni comprese, vanno considerate non attendibili a meno che non arrivino da un server di cui ti fidi. Un server può dire che un tool è di sola lettura. È un'affermazione dentro una stringa, e un server difettoso o malevolo può renderla falsa.
In pratica si traduce in quattro abitudini.
Tratta un server come codice che esegui. Un server stdio è un programma sulla tua macchina con i permessi del tuo account utente. Installarne uno è come installare un qualsiasi pacchetto. Leggi il sorgente o almeno il README, controlla chi lo pubblica e fissa la versione che esegui. I server di riferimento nel repository ufficiale sono un buon punto di partenza, ma leggi che cosa fa ciascuno prima di attivarlo.
Limita gli accessi. Dai al server solo le cartelle, gli account e gli scope che gli servono. Il server filesystem del lab riceve come argomento una directory consentita, e tutto ciò che sta fuori viene rifiutato. I server remoti dovrebbero avere gli scope OAuth più stretti disponibili e token che puoi revocare.
Richiedi l'approvazione per le azioni. I tool di sola lettura e quelli che scrivono, cancellano, inviano o spendono sono categorie diverse. Configura l'host perché chieda conferma prima di eseguire qualsiasi tool che cambia lo stato, e leggi gli argomenti prima di approvare.
Controlla quello che torna indietro. I risultati dei tool e i contenuti delle resource sono dati. Possono contenere testo che sembra un'istruzione per il modello, copiato da una pagina web o da un file. L'host non dovrebbe trattare quel testo come un ordine, e nemmeno tu. Da qui nasce la prompt injection tramite i tool, a cui è dedicato un articolo a parte.
Questo lab usa il server filesystem di riferimento del repository modelcontextprotocol/servers e l'MCP Inspector ufficiale. Non ti servono un modello, una chiave API o un account a pagamento. Ti serve Node.js. L'Inspector richiede Node 22.19.0 o successivo, quindi usa una release LTS corrente. Creerai una cartella, avvierai il server con quella cartella come unica directory consentita e controllerai che cosa ti lascia fare.
Esegui questi comandi nel terminale, dove vuoi tenere il lab. Su Git Bash, Linux o macOS:
mkdir mcp-sandbox && echo 'hello from the sandbox' > mcp-sandbox/note.txtSu PowerShell, lo stesso risultato si ottiene con:
New-Item -ItemType Directory mcp-sandbox | Out-Null
Set-Content -Path mcp-sandbox\note.txt -Value 'hello from the sandbox'Avvia l'Inspector con il server come destinazione:
npx @modelcontextprotocol/inspector npx -y @modelcontextprotocol/server-filesystem ./mcp-sandboxL'Inspector stampa un URL locale che contiene un token valido per questo avvio, e lo apre nel browser. Tieni aperto il terminale, perché il server gira come processo figlio dell'Inspector per tutto il tempo in cui lo usi. Il primo avvio può richiedere un po' di tempo perché npx scarica i pacchetti. Se la connessione fallisce mentre i pacchetti sono ancora in download, aspetta un minuto e riprova. In modalità CLI, --connect-timeout alza il limite, e i comandi qui sotto lo usano.
Nella pagina web, fai clic su Connect. Poi apri la scheda che elenca i tool del server ed esegui l'azione di elenco. Le etichette cambiano tra una versione e l'altra, quindi cerca la scheda e il pulsante che mostrano i tool. Dovresti vedere i tool del filesystem. Sulla release che ho provato, il server di riferimento esponeva sedici tool, tra cui list_directory, read_text_file, write_file e list_allowed_directories. read_file c'è ancora, segnato come deprecato a favore di read_text_file.
Esegui per primo list_allowed_directories. Ti dice che cosa accetterà il server. Il risultato mostra un solo percorso, la posizione assoluta di mcp-sandbox. Nient'altro è raggiungibile.
Seleziona list_directory e passa . come percorso, che indica la directory consentita stessa. Il risultato dovrebbe elencare una sola voce: [FILE] note.txt.
Seleziona read_text_file e passa note.txt come percorso. Il risultato dovrebbe contenere il testo che hai scritto, hello from the sandbox.
Nota il percorso. È note.txt, non ./mcp-sandbox/note.txt. Il server risolve i percorsi relativi rispetto alla sua directory consentita, non rispetto alla cartella da cui hai lanciato l'Inspector. Ho fatto questo errore al primo tentativo. Il server ha restituito un errore "no such file" per un percorso che aveva risolto in mcp-sandbox\mcp-sandbox\note.txt. Il messaggio di errore mi ha mostrato quale percorso aveva usato davvero il server, ed è per questo che i testi di errore vanno letti con attenzione.
Crea un file nella cartella superiore, un livello sopra mcp-sandbox:
echo 'this file is outside the sandbox' > outside.txtTorna nell'Inspector e chiama read_text_file con il percorso ../outside.txt. Aspettati un risultato di errore invece del contenuto del file. Sulla mia macchina il server ha restituito questo testo, con il percorso accorciato:
Access denied - path outside allowed directories: ...\mcplab\outside.txt not in ...\mcplab\mcp-sandboxPoi prova un percorso assoluto verso lo stesso file. Il risultato dovrebbe essere lo stesso rifiuto. Il controllo avviene nel server, sul percorso risolto, quindi la richiesta fallisce comunque tu lo scriva.
Questo è il perimetro in azione. Il server è codice che gira sulla tua macchina con i permessi del tuo utente, eppure non può leggere la cartella superiore, perché è stato avviato con una sola directory consentita e fa rispettare quell'elenco. Se vuoi, prova qualche altro percorso, come .. da solo o una cartella che non esiste, e confronta i testi di errore.
Ho eseguito le stesse chiamate con la modalità CLI dell'Inspector, che invia gli stessi messaggi JSON-RPC del client web:
npx @modelcontextprotocol/inspector --cli --connect-timeout 120000 npx -y @modelcontextprotocol/server-filesystem ./mcp-sandbox --method tools/call --tool-name read_text_file --tool-arg path=note.txtLa risposta è arrivata in JSON, e il contenuto testuale era hello from the sandbox seguito da un a capo. Lo stesso comando con --tool-name list_allowed_directories ha mostrato l'unico percorso consentito. La chiamata a ../outside.txt ha restituito il rifiuto mostrato sopra. Le versioni dei pacchetti il giorno della prova erano @modelcontextprotocol/inspector 2.14.0 e @modelcontextprotocol/server-filesystem 2.2.0. Il server ha stampato Secure MCP Filesystem Server running on stdio su stderr, che è la regola di stdio applicata. Il suo stdout è rimasto riservato ai messaggi del protocollo.
Ho eseguito tutto su Windows 11 con Git Bash e Node 24, e per queste prove non ho usato la pagina web. Le tue versioni e i tuoi percorsi saranno diversi, e l'elenco dei tool può cambiare da una release all'altra.
Trattare MCP come una funzionalità del modello. MCP è un protocollo tra un host e un server. Il modello vede solo ciò che l'host gli passa. Lo stesso server può comportarsi in modo diverso su due host se uno mostra le descrizioni dei tool in modo più chiaro o chiede l'approvazione in un punto diverso.
Confondere un server pubblicato con uno verificato. Installando un server ne esegui il codice. Un pacchetto in un registry pubblico non dice nulla sulla sua sicurezza.
Dare l'accesso in scrittura come impostazione predefinita. Parti in sola lettura. Aggiungi gli scope di scrittura solo quando un compito li richiede.
Stampare su stdout in un server stdio. I log e le stampe di debug scritti su stdout rompono il protocollo. Usa stderr.
Fidarsi delle annotazioni dei tool. Un tool segnato come di sola lettura esegue comunque qualsiasi codice contenga il server.
Sviluppare partendo da un riassunto della specifica. Le revisioni cambiano i nomi dei metodi e le deprecazioni. Controlla la revisione implementata dal tuo SDK e leggi la specifica per i nomi esatti dei campi prima di scrivere codice.
Aspettarsi che l'Inspector faccia un audit. L'Inspector mostra ciò che il server restituisce al client. È una vista di debug, non una revisione di sicurezza.
Leggi prima la panoramica dell'architettura, poi le pagine sui concetti di server e di client. Spiegano le primitive con altri esempi. Dopo, leggi le sezioni della specifica sul protocollo di base e sulla sicurezza, che fissano le regole che ogni server e host deve seguire.
Apri il sorgente del server filesystem di riferimento. È breve, e mostra come un handler controlla i percorsi e restituisce gli errori. Poi scrivi un piccolo server tuo con un solo tool che restituisce una stringa fissa, usando un SDK ufficiale, e ispezionalo con l'Inspector prima di aggiungere qualsiasi cosa che tocchi i tuoi file.
Tieni la cartella del lab piccola e usa e getta, e cancellala quando hai finito. Il prossimo articolo di questo percorso, che cos'è la prompt injection nelle applicazioni LLM, parla dell'attacco reso possibile dai risultati dei tool. Per le basi che questo articolo dà per note, comincia da che cosa sono gli agenti di IA e il tool use.
Agenti di IA per la sicurezza
Metti nella pipeline un modello che non rifiuta, con CVE, advisory e lettura di pagine pubbliche senza costo di token. I tuoi strumenti fanno l'attivo.
Agenti di IA per la sicurezza
Il progetto di un agente di bug bounty: un LLM, dei tool, memoria e guardrail, in un loop che gira sulla tua macchina sotto la tua approvazione.
Agenti di IA per la sicurezza
Un agente di bug bounty in Python con tool calling sull'API NotHoly: propone comandi di recon, aspetta l'approvazione, legge l'output e tiene le note.