Feb 21, 2026·6 min read·8 visits
Ray's dashboard middleware tried to block browser requests by banning POST and PUT. They forgot DELETE. Attackers can use CSRF or DNS rebinding to wipe your running AI jobs.
Ray, the popular open-source framework for scaling AI and Python applications, contained a logic flaw in its dashboard security middleware. While the developers implemented a check to block browser-based state-changing requests (CSRF protection), they explicitly blacklisted `POST` and `PUT` methods but forgot to include `DELETE`. This oversight allows an unauthenticated attacker to trick a victim's browser into deleting jobs, stopping services, and causing a Denial of Service (DoS) on the cluster.
Ray is the heavy lifter of the AI world. It's the engine underneath massive training runs, serving infrastructure, and distributed computing tasks. When you're running a cluster that costs thousands of dollars an hour, availability isn't just a metric; it's money. To manage this beast, Ray exposes a Dashboard—a cockpit for your cluster.
Now, usually, these dashboards bind to 0.0.0.0 or are accessible on a local network. The developers knew that browsers are dangerous. If a developer visits a malicious site while their local Ray dashboard is running, that site shouldn't be able to start crypto miners on the cluster. So, they built a middleware. A bouncer.
This bouncer was told to stop any browser trying to POST or PUT data. It's a classic security approach: "Block the bad stuff." But in the world of vulnerability research, we know that blacklists are destined to fail. If you block the front door and the garage door, you'd better hope you didn't leave the patio door wide open. In Ray's case, they left the DELETE door off the hinges.
The root cause here is a textbook case of Incomplete Filtering. The developers implemented a check called is_browser_request. This utility looks at headers like User-Agent and Origin to decide if a request is coming from a web browser (as opposed to a python script or CLI tool). This is actually a decent heuristic for an internal tool.
The failure happened in how they used it. They wrote logic that essentially said: "If this is a browser, AND it's trying to POST or PUT, stop it." They assumed these were the only methods that could change state or cause harm.
But Ray's API is RESTful. And what does a RESTful API use to remove resources? The DELETE verb. Because DELETE wasn't in the blacklist, the middleware looked at the request, saw it was from a browser, checked the method, saw it wasn't POST or PUT, and waved it through. The code failed to recognize that destruction is just as dangerous as modification.
Let's look at the vulnerable code in dashboard/http_server_head.py. It's almost painful in its simplicity.
# The Vulnerable Logic
if (
# Deny mutating requests from browsers.
dashboard_optional_utils.is_browser_request(request)
# OOPS: We forgot one.
and request.method in [hdrs.METH_POST, hdrs.METH_PUT]
):
return aiohttp.web.Response(
status=405, text="Method Not Allowed for browser traffic."
)If you send a DELETE request, the condition request.method in [...] evaluates to False. The code skips the 405 error and passes the request to the handler. The handler, assuming the request is valid, proceeds to execute the deletion logic.
Here is how they fixed it in version 2.54.0. They switched to a Whitelist approach (allowing only safe methods) or a complete block, depending on the component.
# The Fix: Whitelisting
allowed_methods = {"GET", "HEAD", "OPTIONS"}
if request.method not in allowed_methods:
return aiohttp.web.Response(
status=405, text="Method Not Allowed for browser traffic."
)See the difference? Instead of listing what is bad, they listed what is safe. Anything else—including DELETE, PATCH, or some weird custom HTTP verb—is now blocked by default.
How do we weaponize this? We need a victim developer who has access to the Ray dashboard (e.g., running on localhost:8265 or a corporate LAN IP). We also need that developer to visit our malicious website.
Since modern browsers enforce CORS (Cross-Origin Resource Sharing), a simple fetch with DELETE might trigger a Preflight (OPTIONS) check. However, the most robust attack vector here is DNS Rebinding.
evil.com with a short TTL (Time To Live).evil.com. The DNS initially resolves to the attacker's server, serving a malicious JavaScript payload.evil.com to point to 127.0.0.1 (or the internal IP of the Ray cluster).DELETE /api/jobs/job_12345 request to evil.com. The browser, thinking it's talking to the same origin, allows the request without strict CORS preflight checks (or bypasses them because the Origin matches). The request hits the Ray Dashboard.Because the Ray middleware sees a browser request (User-Agent is 'Mozilla...') but the method is DELETE, it allows it. The Ray API processes the command. The running AI job—perhaps a week-long training session—is instantly terminated.
The CVSS score of 5.9 (Medium) feels low until you consider the context. Ray is infrastructure. It's not just a blog; it's the brain of the operation.
An unauthenticated attacker can:
While there is no data exfiltration (Confidentiality) or code execution (RCE) directly via this CVE, the Availability impact is High. Imagine an adversary sitting in a coffee shop, rebinding DNS, and shutting down the AI models of every developer on the WiFi.
The fix is straightforward, but urgency is key.
127.0.0.1 and not exposed to the wider network (0.0.0.0).--dashboard-auth-token). Use it. This vulnerability relies on the endpoints being unauthenticated.For developers, the lesson is clear: Never use blacklists for security controls. Always define what is allowed, and block everything else by default.
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Ray Anyscale | <= 2.53.0 | 2.54.0 |
| Attribute | Detail |
|---|---|
| CWE | CWE-396 (Technically Incomplete Filtering) |
| CVSS | 5.9 (Medium) |
| Attack Vector | Network (CSRF/DNS Rebinding) |
| Impact | Denial of Service (DoS) |
| Exploit Status | No Known Exploitation |
| Patch | Pull Request #60526 |