Pickle in the Middle: Vertex AI Model Upload Hijacking via GCS Bucket Squatting Enables Cross-Tenant RCE (google-cloud-aiplatform v1.139.0/v1.140.0)
Pickle in the Middle (TL-2026-0825), also tracked as Pickle in the Middle, is a high-severity software vulnerability, first published 2026-06-16. It has no confirmed attribution, affects Google Vertex AI SDK for Python (google-cloud-aiplatform), maps to 19 MITRE ATT&CK techniques (T1036, T1059, T1078), and is covered by 9 detection rules and 23 indicators of compromise.
Key facts for TL-2026-0825
- Threat ID
- TL-2026-0825
- Also known as
- Pickle in the Middle
- Severity
- HIGH
- Status
- PATCHED
- Category
- VULNERABILITY
- First published
- 2026-06-16
- Last reviewed
- 2026-06-16
- Attribution confidence
- NONE
- Motivation
- UNKNOWN
- Target sectors
- technology, artificial-intelligence, cloud-services, financial, healthcare, government
- Target regions
- Global
- Detection rules
- 9
- Indicators of compromise
- 23
Unit 42 disclosed a cross-tenant remote code execution flaw in the Google Cloud Vertex AI SDK for Python (google-cloud-aiplatform). The SDK deterministically derived the default staging bucket name and only checked the bucket's existence, not its ownership, letting an attacker who knows a victim's project ID pre-create ("squat") the predictably-named bucket and replace model artifacts during a ~2.5-second race window. Joblib/pickle deserialization of the poisoned model.joblib then executes attacker code inside Vertex AI's managed serving infrastructure with no initial access to the victim project.
How Pickle in the Middle works
Unit 42 (Palo Alto Networks) researchers identified a cross-tenant remote code execution (RCE) vulnerability in the Google Cloud Vertex AI SDK for Python (PyPI package google-cloud-aiplatform), affecting versions 1.139.0 and 1.140.0. The root cause lives in gcs_utils.py, in the stage_local_data_in_gcs() helper, which constructs the default staging bucket name deterministically as `{project}-vertex-staging-{location}` (for example, "my-project-vertex-staging-us-central1"). When a developer runs standard SDK upload code without explicitly specifying a custom staging_bucket, the SDK derives this name from the caller's project ID and region. Critically, the vulnerable code path used `if not staging_bucket.exists():` to decide whether to create the bucket — it verified only that the bucket existed, never that the caller (or Google's own service agents) actually owned it.
Because project IDs are frequently discoverable and bucket names are globally unique within Google Cloud Storage (GCS), an attacker who knows or guesses a target project ID can pre-register ("squat") the predictably-named staging bucket inside the attacker's own GCP project before the victim ever uploads a model. The attacker grants permissive IAM roles on the squatted bucket (roles/storage.legacyBucketReader, roles/storage.objectCreator, roles/storage.objectViewer) so that the victim's tooling and Google's Vertex AI service agents can read and write to it.
To win the race, the attacker deploys a Cloud Function triggered on the `google.storage.object.finalize` event. When the victim's SDK uploads its model artifact (model.joblib, staged under the vertex_ai_auto_staging/ prefix), the Cloud Function fires and swaps the legitimate artifact for a malicious pickle within a narrow window. Unit 42 measured the timeline: T+0 ms the victim SDK uploads model.joblib (601 bytes); T+804 ms the Cloud Function detects the new object; T+1,433 ms the function replaces the model (601 → 2,945 bytes); T+2,460 ms the Vertex AI Service Agent reads the now-poisoned model — a total exploitation window of roughly 2.5 seconds.
When the victim subsequently deploys the model to an endpoint, the serving container loads the artifact with joblib.load(), which deserializes the pickled Python object. The malicious artifact carries a crafted `__reduce__` method, the canonical pickle code-execution primitive, so deserialization executes arbitrary attacker code inside Vertex AI's managed serving environment. Execution occurs in the context of Vertex AI service identities — the Per-Product Per-Project Service Account (P4SA) `service-PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com` and the tenant-project custom online prediction account `custom-online-prediction@<tenant-project>.iam.gserviceaccount.com`.
Post-exploitation, Unit 42 demonstrated that an exfiltrated access token carrying the broad cloud-platform OAuth scope enabled cross-deployment model theft from GCS buckets, enumeration of and access-control reads against BigQuery datasets and tables, and Cloud Logging access that revealed GKE cluster names, deployment details, and internal container image URIs — a substantial cross-tenant blast radius from a single poisoned model.
The issue was responsibly disclosed to Google on March 5, 2026, prioritized as top severity, and remediated in two stages: v1.144.0 (March 31, 2026) appended a randomly generated uuid4 value to the staging-bucket naming routine to break name predictability, and v1.148.0 (April 15, 2026) added an explicit bucket ownership verification check to gcs_utils.py. Google recommends all developers upgrade to v1.148.0 or later. No CVE, CVSS score, network IOCs, or threat-actor attribution were stated in the source research; none are invented here. This is a proof-of-concept disclosure with no observed in-the-wild exploitation reported.
MITRE ATT&CK techniques used in TL-2026-0825
Defense Evasion
T1036 Masquerading; T1078 Valid Accounts
Execution
T1059 Command and Scripting Interpreter; T1648 Serverless Execution
Discovery
T1082 System Information Discovery; T1526 Cloud Service Discovery; T1580 Cloud Infrastructure Discovery; T1619 Cloud Storage Object Discovery
Initial Access
T1195 Supply Chain Compromise; T1199 Trusted Relationship
Collection
T1213 Data from Information Repositories; T1530 Data from Cloud Storage
Credential Access
T1528 Steal Application Access Token; T1552 Unsecured Credentials
Exfiltration
T1537 Transfer Data to Cloud Account; T1567 Exfiltration Over Web Service
Resource Development
T1583 Acquire Infrastructure; T1587 Develop Capabilities; T1608 Stage Capabilities
Affected products and versions in Pickle in the Middle
- Google — Vertex AI SDK for Python (google-cloud-aiplatform)
Vulnerable versions: 1.139.0; 1.140.0
Fixed in: 1.144.0; 1.148.0 - Google — Google Cloud Vertex AI (managed model serving / endpoints)
Vulnerable versions: affected via SDK staging-bucket flow
Fixed in: mitigated by SDK v1.148.0
Remediation for Pickle in the Middle
Patches
- google-cloud-aiplatform v1.144.0 (uuid4 added to bucket naming routine)
- google-cloud-aiplatform v1.148.0 (bucket ownership verification check in gcs_utils.py)
Immediate actions
- Upgrade google-cloud-aiplatform to v1.148.0 or later (v1.144.0 is the minimum that breaks bucket-name predictability; v1.148.0 adds explicit ownership verification).
- Always pass an explicit, pre-created, project-owned staging_bucket to Vertex AI upload/training calls instead of relying on the auto-derived default.
- Audit GCS for buckets matching the pattern {project}-vertex-staging-{location} that you do not own, and for unexpected IAM grants on staging buckets.
Workarounds
- Explicitly specify a staging_bucket you own when calling the SDK, removing dependence on the deterministic default name.
- Restrict IAM so only owned, verified buckets are usable for Vertex AI staging.
Longer-term hardening
- Enforce least privilege on Vertex AI service agents (P4SA) and the custom online prediction account; avoid broad cloud-platform OAuth scope where possible.
- Prefer safe model serialization formats (e.g., safetensors) over pickle/joblib for model artifacts, and scan model artifacts for unsafe pickle opcodes before deployment.
- Treat project IDs and predictable cloud resource names as sensitive; adopt naming that includes non-guessable entropy and pre-provision required buckets via IaC.
- Deploy AI-SPM / cloud posture monitoring to detect cross-tenant resource squatting and anomalous service-agent token use.
Weaknesses (CWE) in Pickle in the Middle
CWE-502, CWE-639, CWE-345, CWE-362, CWE-340
Timeline of Pickle in the Middle
- Unit 42 reports the cross-tenant RCE vulnerability in the Vertex AI SDK (google-cloud-aiplatform) to Google.
- Google assigns the report top priority.
- Google acknowledges the issue and marks it top severity.
- First fix deployed in google-cloud-aiplatform v1.144.0: a randomly generated uuid4 value is appended to the staging-bucket naming routine to break name predictability.
- Second fix deployed in google-cloud-aiplatform v1.148.0: explicit bucket ownership verification added to gcs_utils.py.
- Unit 42 publicly discloses the 'Pickle in the Middle' research detailing the bucket-squatting, model-poisoning, and pickle-deserialization chain.
- PoC race window T+2,460 ms: the Vertex AI P4SA reads the now-poisoned model from the staging bucket, closing the ~2.5-second exploitation window before joblib.load() executes the payload.
- PoC race window T+1,433 ms: the Cloud Function replaces the legitimate artifact with the malicious pickle RCE payload (601 -> 2,945 bytes).
- PoC race window T+804 ms: the attacker's Cloud Function (triggered on google.storage.object.finalize) detects the newly uploaded model object.
- PoC race window T+0 ms: the victim SDK uploads the legitimate model.joblib (601 bytes) to the attacker-squatted staging bucket.
Sources cited for Pickle in the Middle
- Pickle in the Middle – Hijacking Vertex AI Model Uploads for Cross-Tenant RCE
- Google Cloud Vertex AI Vulnerability Exposes Sensitive Data to Attackers
- Double Agents: Exposing Security Blind Spots in GCP Vertex AI
- ModeLeak: Privilege Escalation to LLM Model Exfiltration in Vertex AI
- Model Namespace Reuse: An AI Supply-Chain Attack Exploiting Model Name Trust
- google-cloud-aiplatform on PyPI (fixed releases v1.144.0 / v1.148.0)
Threats related to Pickle in the Middle
- Google Cloud Vertex AI Python SDK Bucket-Squatting ("Pickle in the Middle") Enables Cross-Tenant Model Hijacking and RCE
- Global Namespace Bucket Hijacking: Universal Cloud Data Exfiltration via Storage Bucket Name Reclamation (AWS S3 / GCP Cloud Storage / Azure Blob)
- CosmosEscape: Gremlin API Sandbox Escape Exposed Platform-Wide Key for Every Azure Cosmos DB Database
- Cloud Bucket Hijacking — Global Namespace Risk: Silent Data-Stream Redirection via Statically-Named Storage Buckets (AWS / Google Cloud / Azure)
- ShutterGap: Ephemeral Public Exposure of AWS RDS/DocumentDB Snapshots, AMIs & SSM Documents Evades CSPM/CNAPP Scan Cycles
- GitLab CE/EE Security Patch Release (19.0.1 / 18.11.4 / 18.10.7) — CVE-2026-4868 GitLab Duo AI Workflow Runner Identity Confusion (CVSS 8.2) Plus DoS and Broken-Authorization Flaws
Detection coverage for TL-2026-0825
As of 2026-06-16, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-0825 across Splunk SPL, Microsoft KQL and Sigma, covering 23 indicator(s) of compromise. The whole corpus is readable without an account; a free account unlocks full detection query text in Splunk SPL, Microsoft KQL and Sigma; paid tiers add raw indicator values, correlation and the MCP server. Threadlinqs MCP server · View plans.