Un guardrail non è un filtro: è una posizione in cui potete fermare qualcosa. La domanda da architetto non è «quale filtro usiamo», ma dove cade la decisione, chi la può scavalcare e che cosa succede quando il controllo stesso non risponde.

Un solo strato non è una difesa

L’impostazione di Anthropic sul contenimento distingue tre superfici: l’ambiente in cui l’agente gira (sandbox, VM, confini del filesystem, controlli in uscita), il modello che consulta (system prompt, classificatori, probe, training) e i contenuti esterni che riesce a raggiungere (permessi degli strumenti, server MCP, plugin di terze parti, ricerca web). La regola che le tiene insieme: «Defenses should overlap and complement each other. When environmental defenses aren’t available, the model layer has to pick up the slack».

Il motivo per cui gli strati non sono ridondanza è formulato in modo scomodo ma corretto: «any probabilistic defense has a non-zero miss rate». Un classificatore, un giudice-modello e un system prompt severo sono tutti difese probabilistiche. È l’argomento da usare quando qualcuno propone di sostituire la sandbox con un prompt migliore: sono due categorie diverse, una deterministica e una statistica, e la prima non si rimpiazza con la seconda.

Screening in ingresso e in uscita

Il pattern documentato per l’ingresso è un modello leggero che pre-classifica prima che l’input raggiunga la conversazione principale: Claude Haiku 4.5 con structured outputs, così che il verdetto sia un valore su cui il codice possa ramificare. Accanto: validazione dell’input contro pattern di injection noti, un system prompt che dichiari i confini e dica come rifiutare, e limitare o bloccare chi ripete lo stesso tentativo.

Sull’uscita, la fuga del prompt merita una nota controcorrente, perché la documentazione raffredda l’entusiasmo: le strategie anti-leak vanno considerate «only when absolutely necessary», dato che aggiungono complessità e possono degradare il resto del compito. L’ordine raccomandato è l’opposto dell’istinto: prima monitorare e filtrare in post-processing, poi semmai irrigidire il prompt. E la mitigazione più economica resta togliere dal prompt i dettagli proprietari di cui il modello non ha bisogno.

Il confine dei contenuti non fidati

È la parte che si sbaglia più spesso, perché è una scelta di formato dei messaggi e non di policy. I contenuti di terze parti — corpo di una mail, pagina web, OCR di un allegato, risultato di uno strumento — vanno consegnati dentro blocchi tool_result, mai nel system prompt né in un blocco di testo utente, perché Claude è addestrato a trattare con scetticismo le istruzioni che compaiono lì. Conviene inoltre codificarli in JSON, così che nessuna virgoletta chiusa ad arte permetta di uscire dal contesto dei dati.

Il rovescio della medaglia è la trappola: «Don’t put your own instructions in tool results». Le vostre istruzioni messe lì possono essere ignorate o segnalate come tentativo di injection, ed è la causa reale di un sintomo che sembra un difetto del modello: Claude che si rifiuta di agire su un risultato o chiede conferma. Le istruzioni vanno nel turno user successivo. Il resto è igiene: privilegio minimo su dati e azioni, screening dei risultati degli strumenti con lo stesso classificatore leggero, e red team con documenti che contengono injection deliberate prima del rilascio.

Controlli deterministici: permessi e hook

Sui Managed Agents la politica è esplicita e ha default asimmetrici da conoscere: always_allow esegue senza conferma, always_ask mette la sessione in pausa in attesa di approvazione; il toolset dell’agente ha per default always_allow, mentre i toolset MCP hanno per default always_ask, così che un nuovo strumento aggiunto a un server MCP non entri in esecuzione senza approvazione. La granularità utile è quella per singolo strumento: consentire l’intero toolset e richiedere conferma solo su bash.

In Claude Code lo stesso lavoro lo fanno gli hook. Un hook PreToolUse può bloccare la chiamata uscendo con codice 2 oppure restituendo deny, e quando più hook rispondono vince il verdetto più restrittivo, nell’ordine deny, defer, ask, allow. Un dettaglio operativo da scrivere nel design: «One hook returning deny doesn’t stop sibling hooks from executing». Gli effetti collaterali degli altri hook avvengono comunque.

Il guardrail centralizzato, e dove finisce

Per le organizzazioni Claude Enterprise c’è un punto di controllo che non vive sui dispositivi: gli Inference hooks instradano ogni prompt governato verso un server di sicurezza dell’organizzazione, che risponde allow o deny prima che l’inferenza parta. Girano sui server di Anthropic, quindi non c’è nulla da installare; il timeout del verdetto è di 5 secondi per default; e se il vostro server non risponde è una vostra impostazione a decidere se bloccare la richiesta o lasciarla passare senza ispezione. L’adozione può partire in shadow mode e su una percentuale di traffico.

I limiti vanno dichiarati insieme alla funzione, perché sono di progetto: «Verdicts are allow or deny. Rewriting or redacting a prompt is not supported», i byte grezzi di immagini e file non vengono inviati (quindi lo screenshot di un documento non è ispezionato), l’unico evento oggi è il prompt — l’applicazione lato risposta è prevista in seguito — e la funzione non è disponibile su Amazon Bedrock né su Google Cloud. Da ultimo, un guardrail del modello che il vostro codice deve gestire: un rifiuto dei classificatori di sicurezza torna con stop_reason uguale a refusal come normale risposta HTTP 200, non come errore. Un client che guarda solo lo status code lo archivia come successo.