Quanti team stanno collegando agenti AI a Slack, a un’interfaccia web o a server MCP proteggendo l’accesso solo con un prompt di sistema ben scritto? Secondo un’analisi pubblicata su DZone e basata su findings del Red Team di NVIDIA, è proprio questo l’errore architetturale più diffuso nelle implementazioni enterprise di agenti AI: “i guardrail basati sul prompt falliscono sotto pressione avversaria”. Un attaccante sufficientemente motivato può camuffare attività malevole da comportamenti legittimi, scalare privilegi gradualmente o nascondere esecuzione di codice dentro interazioni apparentemente normali.
Il punto chiave, riassunto efficacemente dall’articolo originale, è questo: il modello non è il punto di applicazione della sicurezza, è la cosa che va difesa. Va trattato come qualsiasi altro componente non fidato della vostra infrastruttura — proprio come fareste con un processo che esegue codice arbitrario ricevuto da input esterni. In questo articolo ripercorriamo i cinque controlli infrastrutturali proposti, con esempi pratici applicabili su Kubernetes e nello stack Microsoft.
1. Identità e propagazione dell’autenticazione
Il primo errore comune è usare credenziali condivise per l’agente, indipendentemente da chi lo stia effettivamente invocando (via Slack, web UI o endpoint MCP). Questo rende impossibile distinguere un’azione legittima da un abuso e complica ogni audit successivo.
La soluzione è propagare l’identità dell’utente umano fino ai sistemi a valle, invece di far agire l’agente con un account di servizio onnipotente. Lo standard di riferimento è OAuth 2.0 Token Exchange (RFC 8693), che permette di scambiare il token dell’utente con un token downstream a scope ridotto e vita breve:
POST /oauth2/token HTTP/1.1
Host: identity.contoso.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token={USER_TOKEN}
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&requested_token_type=urn:ietf:params:oauth:token-type:access_token
&audience=ticketing-api
&scope=tickets.read tickets.comment
Il token risultante è specifico per l’audience richiesta (in questo caso l’API di ticketing), ha uno scope minimo e una scadenza breve. Ogni chiamata a valle porta con sé l’identità originale dell’utente, non quella generica dell’agente: questo è ciò che rende possibile un audit trail affidabile.
2. Presupporre l’esecuzione di codice e limitarne gli effetti
Un agente con accesso a strumenti di code execution va trattato esattamente come un processo che esegue input non fidato, perché di fatto è quello che è. I controlli minimi da applicare a livello di container:
- filesystem di root read-only;
noexecsu tutti i mount scrivibili, per impedire l’esecuzione di binari scaricati a runtime;- drop di tutte le capability Linux non strettamente necessarie;
- configurazione dell’agente montata come read-only da un mount point separato, così che l’agente stesso non possa alterare la propria configurazione;
- allowlist esplicita dei binari eseguibili.
Un esempio di `securityContext` Kubernetes coerente con questi principi:
securityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
# mount separato per lo storage scrivibile, con noexec applicato a livello di nodo
- name: agent-config
mountPath: /etc/agent
readOnly: true
3. Egress default-deny
Un agente compromesso o manipolato tramite prompt injection che possa raggiungere qualunque host su Internet è un rischio enorme: esfiltrazione dati, comando e controllo, o accesso agli endpoint di metadata del cloud provider (il classico 169.254.169.254, spesso usato per rubare credenziali IAM). La difesa è una NetworkPolicy Kubernetes default-deny in uscita, con eccezioni esplicite solo verso ciò che serve realmente:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ai-agent-default-deny-egress
namespace: agents
spec:
podSelector:
matchLabels:
app: ai-agent
policyTypes:
- Egress
egress:
# consente solo DNS e il proxy autenticato interno
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
- to:
- podSelector:
matchLabels:
app: egress-proxy
ports:
- protocol: TCP
port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: block-cloud-metadata
namespace: agents
spec:
podSelector:
matchLabels:
app: ai-agent
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 169.254.169.254/32
Le connessioni realmente necessarie devono passare attraverso un proxy autenticante con allowlist basata su FQDN, con logging completo di ogni richiesta e dell’identità utente associata: in questo modo ogni chiamata in uscita è tracciabile e limitata a destinazioni note.
4. Nessun segreto persistente
Iniettare segreti tramite variabili d’ambiente, file di configurazione o, peggio, direttamente nel context window del modello è una pratica rischiosa: un agente che legge il proprio ambiente, o che viene indotto a farlo tramite prompt injection, può esfiltrare quei segreti con facilità.
L’approccio consigliato è il token brokering per singolo task, con TTL molto brevi (minuti, non ore) e revoca esplicita al completamento del task, non solo alla scadenza naturale:
- ogni task riceve un token appena sufficiente per l’operazione richiesta;
- il token viene revocato non appena il task termina, indipendentemente dalla sua scadenza nominale;
- ogni emissione di segreto viene registrata con l’identità dell’utente umano che ha originato la richiesta.
Strumenti come Azure Key Vault (con identità gestite e token a vita breve) o soluzioni dedicate di secret brokering per workload agentic vanno preferiti rispetto a qualunque forma di credential injection statica.
5. Controllo della supply chain dei pacchetti
Un agente con capacità di installare pacchetti (npm, pip, NuGet) durante l’esecuzione è una superficie di attacco enorme, soprattutto se può installare da repository VCS arbitrari o eseguire script di post-install non controllati. I controlli minimi:
- uso di repository proxy interni (Artifactory o equivalente) come unica fonte consentita;
- blocco esplicito delle installazioni da URL o VCS diretti (es.
pip install git+https://...); - abilitazione di
ignore-scripts=trueper prevenire l’esecuzione di script post-install, un vettore di attacco noto nell’ecosistema npm; - verifica dell’hash dei pacchetti installati.
# .npmrc per l'ambiente dell'agente
registry=https://artifactory.contoso.com/api/npm/npm-proxy/
ignore-scripts=true
audit=true
Validare i controlli con test automatici, non con documentazione
Il consiglio più pratico dell’articolo è forse questo: questi cinque controlli vanno implementati come test case automatici nella pipeline CI/CD, non lasciati a una checklist di sicurezza scritta a mano. Alcuni esempi di assertion da includere:
- un chiamante non autenticato deve essere rifiutato;
- un tentativo di scrittura su file di configurazione nascosti (dotfile) deve fallire;
- ogni connessione in uscita non allowlisted deve essere bloccata e loggata;
- nessun segreto deve essere presente nelle variabili d’ambiente del processo agente;
- l’endpoint di metadata cloud deve risultare irraggiungibile;
- un’installazione di pacchetto da VCS diretto deve essere bloccata dal proxy.
Conclusione
Gli agenti AI non introducono nuovi principi di sicurezza: richiedono di applicare con rigore quelli che già conosciamo — least privilege, isolamento, gestione dei segreti a vita breve, egress controllato — a un tipo di workload che, per sua natura, esegue codice e prende decisioni sulla base di input non completamente prevedibili. Chi gestisce infrastrutture Kubernetes o Azure ha già gli strumenti per implementare questi controlli; il passo mancante, spesso, è semplicemente la decisione di applicarli con la stessa serietà riservata a qualunque altro workload che esegue codice non fidato.
Fonte originale: “5 Infrastructure Controls for Securing AI Agents” su DZone.