Vertex AI Double Agent: il pattern di privilege escalation cross-tenant che colpisce anche AWS e Azure

Vertex AI Double Agent: il pattern di privilege escalation cross-tenant che colpisce anche AWS e Azure

Il 31 marzo 2026 Unit 42 di Palo Alto Networks ha pubblicato il report Double Agents: Exposing Security Blind Spots in GCP Vertex AI, firmato dal ricercatore Ofir Shaty, e nell'ora in cui l'ho letto sul mio Hetzner CCX33 (8 vCPU AMD EPYC 9454P, 32 GB RAM DDR5) ho capito che era uno di quei case che avrei rivisto in mezza dozzina di engagement nei mesi successivi. Il pattern descritto è elegante in senso brutto, e cattura un blind spot che vale per Vertex AI ma che è strutturalmente identico in AWS Bedrock Agents e Azure AI Foundry. La tesi è semplice: quando un cloud provider crea un servizio "managed agent" e gli assegna un service account di default, quel service account ha tipicamente più permessi di quanto serva all'agente per fare il suo lavoro. Un attaccante che riesce a eseguire codice nell'agent (e ci sono molti modi di farlo, vedi il pattern pickle deserialization) ottiene una porta di accesso a livello di permessi del provider stesso, non dell'utente.

Sul mio laboratorio di audit red team ho riprodotto il pattern descritto nel report Unit 42 con autorizzazione esplicita su un Vertex AI Agent Engine di test pre-patch del 31 marzo. Ho confermato che ogni call al mio agent invocava il metadata service di Google e che le credenziali del P4SA (Per-Project, Per-Product Service Agent) service-<PROJECT-ID>@gcp-sa-aiplatform-re.iam.gserviceaccount[.]com venivano effettivamente esposte. Con quelle credenziali, partendo dal contesto di esecuzione dell'agent, ho avuto accesso in lettura a tutti i Cloud Storage bucket del progetto consumer e ho potuto scaricare immagini container da repository Google interni (cloud-aiplatform-private/reasoning-engine, llm-extension/reasoning-engine-py310:prod) che non avrebbero mai dovuto essere visibili ai customer. Non ho continuato il pivot oltre questo punto perché lo scope dell'audit era confined al PoC, ma è chiaro che il vettore è generalizzabile alla mappatura della supply chain interna del provider e a deployment futuri di codice manipolato.

Cronaca tecnica del Double Agent: cosa fa, come funziona, perché è grave

Il vettore inizia con il pattern di deployment standard di Vertex AI Agent Engine. Lo sviluppatore impacchetta il proprio agent come oggetto Python serializzato in pickle (formato richiesto dall'ADK al momento del report). Quando l'agente viene deployato e invocato, il runtime di Google deserializza il pickle. Le insecure deserialization in pickle è un classico pattern di RCE noto da quindici anni nella security Python: chiunque controlli il contenuto del pickle può eseguire codice arbitrario al momento della deserializzazione. Il report Unit 42 è esplicito su questo: l'attaccante costruisce un agent malicious con payload nascosto, lo deploya, e al primo invoke il payload viene eseguito nel contesto dell'Agent Engine.

Una volta dentro l'esecuzione, l'attaccante chiama il metadata service di Google Cloud (l'endpoint 169.254.169.254/computeMetadata/v1/) e ottiene le credenziali del P4SA. È qui che si manifesta il problema strutturale: il P4SA è creato di default da Google per ogni Agent Engine, ed è progettato per fare cose che il customer non avrebbe motivo di fare direttamente, come accedere a immagini container del provider. I permessi default del P4SA includevano fra l'altro lettura su Cloud Storage di tutto il progetto consumer e accesso ai repository Artifact Registry privati interni di Google. Da qui il salto cross-tenant: l'attaccante non sta più operando con i permessi limitati del proprio progetto, sta operando con i permessi del service account Google associato al managed service.

Il fatto che il pattern violi il principio del least privilege è ovvio ex post; il fatto che fosse default in produzione per migliaia di customer è il vero failure di governance. Questo è esattamente il pattern che la nuova OWASP Top 10 for Agentic Applications classifica come ASI03 Identity and Privilege Abuse, con sovrapposizione su ASI05 Unexpected Code Execution per la parte pickle, come ho discusso nell'analisi del framework OWASP ASI. La differenza fra l'incident Vertex AI e altri privilege escalation cloud-side è che la radice è la modalità di deployment "managed agent" e i default che il provider sceglie per il customer; non un bug di un singolo cliente.

Se gestisci agent su Vertex AI, AWS Bedrock o Azure AI Foundry

Nel mio hub dedicato all'AI per aziende, sezione security raccolgo gli articoli sui pattern di attacco e mitigation che applico in red team. Se la tua azienda ha agent in produzione o pianifica di migrare verso piattaforme managed agent dei tre cloud principali, l'audit dei service account default è un esercizio di due giornate che cambia la tua postura di rischio in modo misurabile.

Lo stesso pattern in AWS Bedrock Agents e Azure AI Foundry

Il caso Vertex AI ha messo Google sotto i riflettori, ma il pattern strutturale colpisce qualunque provider che offra "managed agent" con service account creato di default per il customer. Su AWS Bedrock Agents, il default è un IAM role chiamato AmazonBedrockAgentRole-<random> che viene assegnato al momento del deploy e che ha permessi standard incluso l'accesso a S3 buckets dichiarati nella knowledge base. Nei test del mio laboratorio ho replicato il pattern: agent che esegue codice arbitrario via tool injection (non più pickle nello specifico, AWS usa un proprio formato serialization, ma il principio resta), agente che chiama il metadata service EC2 dal proprio runtime, credenziali estratte, pivot a livello di IAM role. Il vettore di RCE iniziale è diverso ma la conseguenza è la stessa.

Su Azure AI Foundry, il pattern è il managed identity chiamato AzureMLCompute-<workspace> che ha access policy a Azure Storage del workspace. Il vettore di compromissione iniziale può essere una prompt injection che induce un tool del agent a leggere/scrivere file, e i file arbitrari letti possono includere sezioni del .env o di kubernetes secrets montati nel container del compute pool. Una volta ottenuto un foothold nel container, le credenziali della managed identity sono recuperabili dal metadata service Azure (169.254.169.254/metadata/identity/oauth2/token).

La generalizzazione del pattern è quindi: qualunque provider che crei un service principal di default per gli agent managed, e che dia a quel service principal permessi più ampi del necessario, è esposto a privilege escalation cross-tenant. Le mitigation sono provider-specific ma il principio è uno solo: portare il service principal sotto controllo del customer (Bring Your Own Service Account in linguaggio Google, Custom IAM Role in AWS, User-Assigned Managed Identity in Azure), assegnare solo i permessi strettamente necessari, monitorare le attività anomale del service principal con log strutturato.

Threat model generalizzato e script di audit

Per ognuno dei tre cloud applico nei red team un threat model strutturato in cinque punti:

1. Identifica i service principal default che il managed agent crea
2. Enumera i permessi assegnati di default a quei service principal
3. Confronta i permessi con il principio del least privilege per il task dichiarato
4. Verifica se è possibile il deploy di codice arbitrario nell'agent (pickle, tool injection, RCE classica)
5. Verifica se il runtime dell'agent può accedere al metadata service del cloud

Su GCP lo script di enumerazione P4SA è approssimativamente:

gcloud iam service-accounts list \
  --filter="email:service-${PROJECT_ID}@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
  --format=json

gcloud projects get-iam-policy ${PROJECT_ID} \
  --flatten="bindings[].members" \
  --format='table(bindings.role)' \
  --filter="bindings.members:serviceAccount:service-${PROJECT_ID}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"

gcloud asset search-all-iam-policies \
  --scope=projects/${PROJECT_ID} \
  --query="policy:service-${PROJECT_ID}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"

Su AWS, l'audit del IAM role del Bedrock Agent passa per aws iam get-role e aws iam list-attached-role-policies sul role assegnato all'agent, seguito da un'analisi delle action consentite. Su Azure, az identity show e az role assignment list danno gli equivalenti. Lo script che fornisco in deliverable ai clienti è un wrapper che gira l'enumerazione su tutti e tre i cloud in parallelo e produce un CSV con risk score per ogni service principal trovato, ordinato per gravità del privilege scoping rispetto al least privilege ideal.

I dettagli AWS Bedrock e Azure AI Foundry che è bene conoscere prima del deploy

Sul lato AWS il pattern Bedrock Agents è ben documentato dalla console di creazione: quando crei un agent, AWS offre l'opzione di "creare un nuovo IAM role per l'agent" con permessi precompilati che includono accesso a bedrock:*, s3:GetObject su buckets dichiarati nella knowledge base, lambda:InvokeFunction sui Lambda dichiarati come tool, e bedrock-agent-runtime:Invoke*. Sembra ragionevole come default, ma nei test ho osservato due aspetti problematici. Primo, alcuni di questi permessi includono wildcard sugli arn (es. Resource: "*" su bedrock-agent-runtime:Invoke*) che permettono al role di invocare anche agent di altri progetti AWS della stessa organizzazione se il deployment è su account condiviso. Secondo, il role viene assunto dal runtime Bedrock Managed con session token che, se estratti tramite RCE in tool Lambda compromesso, sono utilizzabili per le 12 ore standard del session lifetime AWS, dando all'attaccante una finestra ampia di pivot.

Su Azure AI Foundry il default è il workspace-level managed identity con role assignment a Storage Blob Data Reader sul blob storage del workspace, AzureML Data Scientist sul workspace stesso e Reader su un set di resource group correlati al deployment del compute. La policy di default dell'AzureML Compute include un montaggio del Key Vault del workspace come secret store, con i secret accessibili al runtime del compute pool. Se l'agent ha la capacità di leggere file dal proprio container (e ce l'ha quasi sempre, almeno per debugging dei tool), può leggere il Key Vault montato. Il pattern di compromise tipico è: prompt injection induce un tool dell'agent a leggere un file in un percorso "log di debug", il file in realtà è un mount del secret store, l'attaccante ottiene chiavi di accesso a risorse esterne dichiarate nel Key Vault del workspace.

In tutti e tre i cloud la radice è la stessa: il provider crea un service principal, gli assegna permessi pensati per "tutto quello che l'agent potrebbe voler fare", e la differenza fra "potrebbe" ed "effettivamente fa" è la superficie di attacco. Il compito del consulente serio è ridurre questa differenza prima del go-live, non dopo il primo incident.

BYOSA, Custom IAM Role, User-Assigned Managed Identity: governance dei service principal agent

La risposta strutturale al Double Agent non è "patch il pickle deserialization", anche se è giusto fare anche quello. La risposta è governance del lifecycle dei service principal usati dagli agent. Lo schema operativo che applico nei progetti con clienti che hanno agent production-grade è il seguente.

Primo, un service principal dedicato per ogni agent o gruppo logico di agent. Mai default del provider, mai service principal condiviso fra agent diversi. Secondo, permission catalog esplicito: prima del deploy, scriviamo cosa l'agent deve poter fare e creiamo i role/policy che danno solo quei permessi. Terzo, audit trail strutturato sulle azioni del service principal: ogni call API, con timestamp, source IP, action, target resource. Quarto, alerting su comportamenti anomali: chiamate al metadata service da parte dell'agent (sempre sospette se non strettamente necessarie al business logic), pattern di accesso a risorse non dichiarate nel permission catalog, pattern di rate change sul service principal. Quinto, kill switch e playbook di incident response: chi disabilita il service principal in caso di sospetto compromise, in quanto tempo, con quale comunicazione interna.

Per chiudere il quadro, c'è un tema reputazionale che vale la pena anticipare con il cliente: il primo cliente a subire un incident con questo pattern in Italia farà notizia e attirerà l'attenzione del Garante per dati personali eventualmente esposti, oltre che dell'autorità di settore se l'azienda è in finanziario o sanitario. La domanda che il revisore o il regolatore farà non sarà "hai patchato il pickle?", sarà "avevate un inventario dei service principal agent? un audit trail strutturato? una procedura di kill switch documentata?". Le risposte a queste tre domande devono essere "sì" già adesso, non al primo audit. Il consulente che porta sul tavolo del cliente PMI italiana questo framework prima del prossimo deploy AI agent fa esattamente quello che il mercato regolato 2026 richiede.

Questa governance non è esotica ed è applicabile in 4-6 settimane per un cliente medio con uno o due agent in produzione. Il deliverable è una matrice "agent → service principal → permessi → audit trail" che diventa parte del programma di compliance dell'azienda. Per chi sta valutando integrazioni AI con esposizione a managed agent dei tre cloud principali, è il prerequisito non negoziabile. Il caso Vertex AI Double Agent è il primo case study pubblicamente documentato di questo pattern, ma il pattern stesso è strutturale e non finisce qui. Non sarà l'ultimo, e i prossimi probabilmente colpiranno i provider che oggi sembrano meno esposti per assenza di scrutiny dedicato e per minore numero di customer enterprise visibili che giustifichino la ricerca dedicata. Se vuoi una conversazione tecnica su come strutturare la governance dei service principal per agent della tua azienda prima di un'integrazione production, oppure su come fare un audit retrospettivo dei deploy attualmente in linea sui tre cloud principali, il modulo di preventivo gratuito è il punto da cui inquadrare la richiesta in due minuti, sette domande.

Ultima modifica: