VYPR
Moderate severityOSV Advisory· Published Jan 16, 2026· Updated Jan 16, 2026

Dask distributed Vulnerable to Remote Code Execution via Jupyter Proxy and Dashboard

CVE-2026-23528

Description

Dask distributed is a distributed task scheduler for Dask. Prior to 2026.1.0, when Jupyter Lab, jupyter-server-proxy, and Dask distributed are all run together, it is possible to craft a URL which will result in code being executed by Jupyter due to a cross-side-scripting (XSS) bug in the Dask dashboard. It is possible for attackers to craft a phishing URL that assumes Jupyter Lab and Dask may be running on localhost and using default ports. If a user clicks on the malicious link it will open an error page in the Dask Dashboard via the Jupyter Lab proxy which will cause code to be executed by the default Jupyter Python kernel. This vulnerability is fixed in 2026.1.0.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

An XSS vulnerability in Dask distributed prior to 2026.1.0 allows remote code execution via crafted URLs when used with Jupyter Lab and jupyter-server-proxy.

Vulnerability

Overview

CVE-2026-23528 is a cross-site scripting (XSS) vulnerability in the Dask distributed dashboard that can lead to remote code execution when Dask is used alongside Jupyter Lab and jupyter-server-proxy [1][3]. The root cause is improper escaping of user-controlled input in the dashboard's proxy endpoint, specifically in the http_get handler where the worker variable is inserted into an error message without HTML escaping [4]. Prior to the fix, the code used string formatting (% worker) that did not sanitize special characters, allowing an attacker to inject arbitrary HTML or JavaScript [4].

Attack

Vector and Exploitation

To exploit this vulnerability, an attacker must craft a phishing URL that targets a local setup where Jupyter Lab (with jupyter-server-proxy) and a) and a Dask distributed cluster are running on default ports (typically 8888 and 8787 respectively) [1][3]. If a user clicks the malicious link, it triggers an error page in the Dask Dashboard served through the Jupyter Lab proxy, and the injected script executes in the context of the Jupyter environment [1][3]. The attack does not require authentication to the Dask dashboard, but relies on the user being logged into Jupyter Lab and clicking the crafted link [3].

Impact

Successful exploitation allows an attacker to execute arbitrary code in the default Jupyter Python kernel [1][3]. This means the attacker can run any Python code with the privileges of the Jupyter user, potentially leading to data theft, installation of malware, or further lateral movement within the network. The vulnerability is rated with a CVSS v4.0 score (pending NVD assessment) but is considered critical due to the remote code execution of arbitrary code [1].

Mitigation and

Patches

The vulnerability is fixed in Dask distributed version 2026.1.0 (and later 2026.1.1) [1][3]. Users should upgrade immediately. There are no complete workarounds, but uninstalling jupyter-server-proxy and accessing the Dask dashboard directly reduces the risk to only XSS (without RCE) [3]. Running Jupyter and Dask on non-default ports can also reduce the likelihood of exploitation surface, though it does not eliminate the vulnerability [3]. The fix involves using html.escape() on the worker string before including it in the error message [4].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
distributedPyPI
< 2026.1.02026.1.0

Affected products

2
  • Dask/DistributedOSV2 versions
    1.1.0, 1.10.0, 1.10.10, …+ 1 more
    • (no CPE)range: 1.1.0, 1.10.0, 1.10.10, …
    • (no CPE)range: <2026.1.0

Patches

1
ab72092a8a93

Merge commit from fork

https://github.com/dask/distributedJacob TomlinsonJan 16, 2026via ghsa
2 files changed · +13 1
  • distributed/dashboard/tests/test_scheduler_bokeh.py+11 0 modified
    @@ -1099,6 +1099,17 @@ async def test_proxy_to_workers(c, s, a, b):
             assert response_direct.code == 200
             assert b"System" in response_direct.body
     
    +    if proxy_exists:
    +        dashboard_port = s.http_server.port
    +        http_client = AsyncHTTPClient()
    +        unsafe_host = "<><><>"  # Some unsafe characters that should be escaped
    +        proxy_url = f"http://localhost:{dashboard_port}/proxy/1234/{unsafe_host}/status"
    +        response = await http_client.fetch(proxy_url, raise_error=False)
    +        assert response.code == 400
    +        assert (
    +            unsafe_host not in response.body.decode()
    +        ), "Unsafe characters should be escaped"
    +
     
     @gen_cluster(
         client=True,
    
  • distributed/http/proxy.py+2 1 modified
    @@ -1,5 +1,6 @@
     from __future__ import annotations
     
    +import html
     import logging
     
     from tornado import web
    @@ -46,7 +47,7 @@ async def http_get(self, port, host, proxied_path):
     
                 worker = f"{self.host}:{port}"
                 if not check_worker_dashboard_exits(self.scheduler, worker):
    -                msg = "Worker <%s> does not exist" % worker
    +                msg = f"Worker &lt;{html.escape(worker)}&gt; does not exist"
                     self.set_status(400)
                     self.finish(msg)
                     return
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.