Pickle in the Middle — Google Cloud Vertex AI SDK bucket-squatting enables cross-tenant model hijack and RCE (patched), plus an unrelated stored-XSS CVE in the same SDK
TL;DR
Palo Alto Networks Unit 42 disclosed "Pickle in the Middle": the Python google-cloud-aiplatform SDK (Google Cloud Vertex AI) picked a predictable, unowned-by-default staging bucket name for model uploads ({project}-vertex-staging-{region}), so an attacker could pre-create that bucket in their own GCP project, wait for a victim to upload a model without specifying staging_bucket explicitly, silently swap in a malicious pickled model, and get arbitrary code execution inside Google's own model-serving infrastructure the moment Vertex AI deserializes it — no access to the victim's project and no social engineering required. Fixed across two releases: v1.144.0 (2026-03-31, randomized bucket naming) and v1.148.0 (2026-04-15, added bucket-ownership verification). Update (2026-08-08): a second, unrelated bug in the same SDK — CVE-2026-2472, an unauthenticated stored XSS in the evaluation-results visualizer — was folded in below; it affects a different version range and requires a separate upgrade.
What happened
Unit 42 reported the flaw to Google's Vulnerability Reward Program on 2026-03-05; Google assigned it top priority within days.
The mechanism
- Predictable bucket naming. When a caller doesn't explicitly set
staging_bucket, the SDK derives a Cloud Storage bucket name deterministically:{project}-vertex-staging-{region}. An attacker who knows (or guesses) a target's GCP project ID and region can compute this name in advance. - No ownership check. The SDK calls
staging_bucket.exists()before uploading — but a bucket name that exists in any GCP project satisfies that check, not just one owned by the caller. An attacker pre-creates a bucket with the predicted name in their own project; the victim's SDK then silently uploads the victim's model artifacts into the attacker's bucket. - The race and the swap. Unit 42 measured roughly 2.5 seconds between a victim's model upload completing and Vertex AI reading the file to deploy it. In their proof of concept, a Cloud Function triggered on the upload event replaced the legitimate model with a malicious one in 1.4 seconds — comfortably inside that window.
- Pickle deserialization → RCE. Vertex AI models are commonly serialized with
pickle/joblib. Pickle's__reduce__mechanism lets a crafted payload execute arbitrary code the moment the file is deserialized — so the swapped-in "model" runs attacker code the instant Vertex AI's serving infrastructure loads it, inside Google's own execution environment, with no interaction from the victim required beyond the original upload.
This chains a classic bucket-squatting/name-guessing weakness (the same class of bug as any cloud service that derives resource names predictably from a project ID) with the well-known pickle-deserialization RCE primitive, applied to an ML model-serving pipeline specifically — a cross-tenant compromise vector unique to the shared-infrastructure nature of a managed AI platform.
Affected versions and fix
- Affected:
google-cloud-aiplatformSDK versions 1.139.0 and 1.140.0 were the versions Unit 42 tested against and confirmed vulnerable (earlier versions using the same bucket-naming scheme are likely affected too, though not explicitly enumerated in the primary source). - Fix, in two stages:
- v1.144.0 (2026-03-31) — added a random UUID4 suffix to auto-generated staging bucket names, eliminating predictability.
- v1.148.0 (2026-04-15) — added explicit bucket-ownership verification in
Model.upload(), closing the bucket-squatting primitive even if a name were somehow guessed.
No CVE identifier or CVSS score was published alongside the primary disclosure as of this writing.
Am I affected?
pip show google-cloud-aiplatform 2>/dev/null | grep -E '^(Name|Version):'
You're exposed if you're running google-cloud-aiplatform < 1.148.0 and any of your team's code calls Model.upload() (or equivalent SDK model-upload paths) without explicitly setting the staging_bucket parameter to a Cloud Storage location you control.
If you are affected
- Upgrade to
google-cloud-aiplatform≥ 1.148.0. - Always pass an explicit
staging_bucketpointing at a bucket you own, rather than relying on the SDK's auto-generated default — this is Google's own stated best practice going forward, independent of the patch. - If you uploaded models on an affected SDK version before April 2026, audit those model artifacts for signs of tampering (unexpected file sizes, unfamiliar pickle opcodes, deploy logs showing unexpected serving-container behavior) and consider re-uploading from a clean, patched environment.
- → playbooks/rotating-cloud-credentials.md — if you suspect exploitation, treat the Vertex AI serving environment's own service-account credentials as potentially exposed, since attacker code would have run with that environment's privileges.
Update — 2026-08-08: CVE-2026-2472, unrelated stored XSS in the same SDK
A separate, unrelated bug in google-cloud-aiplatform — CVE-2026-2472 (GCP advisory GCP-2026-011) — is an unauthenticated stored cross-site scripting flaw in the SDK's _genai/_evals_visualization.py module, which renders model-evaluation results and dataset JSON inside Jupyter and Google Colab notebooks. The renderer embeds evaluation-result JSON directly into an HTML <script> block without escaping </script> sequences, so a crafted evaluation result or dataset field (e.g. a prompt string containing </script><script>alert('XSS')</script>) breaks out of the script context and executes arbitrary JavaScript in the notebook's browser session the moment results are displayed — no authentication needed beyond whatever produced the evaluation data in the first place. Affected: 1.98.0 up to (but not including) 1.131.0. Fixed in 1.131.0. A public proof-of-concept is available. This is a distinct root cause (XSS via unescaped JSON-in-HTML) from the pickle-deserialization RCE above, and a distinct affected-version range — check both independently.
pip show google-cloud-aiplatform 2>/dev/null | grep -E '^Version:'
You're exposed to CVE-2026-2472 if your version is >= 1.98.0 and < 1.131.0 and you view model-evaluation results in a Jupyter/Colab notebook using this SDK's visualization helpers, especially against evaluation data or datasets you didn't author yourself. Upgrade to ≥ 1.131.0.
Prevention
→ prevention/supply-chain-attack-surface.md
- Never let a cloud SDK derive a resource name it will subsequently trust from data an attacker could also predict (project ID + region, in this case) without also verifying ownership of that resource.
- Avoid pickle/joblib for any model-serialization path that crosses a trust boundary (upload, download, or transfer between environments) — prefer formats that don't support arbitrary code execution on load (e.g., ONNX, SafeTensors) where the serving framework supports them.
- Treat any managed AI platform's shared-infrastructure staging/upload path as a cross-tenant attack surface, not just a private pipe to your own project — the same caution this repo already applies to shared-execution-environment platforms like Dialogflow CX (Rogue Agent).
Sources
- Unit 42 (Palo Alto Networks) — Pickle in the Middle: Hijacking Vertex AI Model Uploads for Cross-Tenant RCE — primary technical disclosure, PoC timing data, fix commits.
- The Hacker News — Google Vertex AI SDK Flaw Let Attackers Hijack Model Uploads via Bucket Squatting — independent corroboration, disclosure timeline.
- GitLab Advisory Database — CVE-2026-2472: Google Cloud Vertex AI SDK affected by Stored Cross-Site Scripting (XSS) — canonical affected/patched version range for the XSS finding.
- SentinelOne Vulnerability Database — CVE-2026-2472 — independent corroboration of the finding and GCP-2026-011 advisory reference.