Almost every attack surface inventory starts with the same question: what is exposed to the internet? It is the right question, and it leaves out exactly the kind of flaw CISA added to the Known Exploited Vulnerabilities catalog on August 17, 2026. CVE-2025-62593 affects Ray, the distributed computing framework used to train and serve AI models, and it needs no port open to the world. It needs a developer to open a browser tab.

The flaw in one sentence
CVE-2025-62593 is a code injection issue (CWE-94, combined with CWE-352, cross-site request forgery) that lets a malicious website send requests to the Ray dashboard and API running on a developer's machine, all the way to arbitrary command execution. NVD assigns a CVSS 4.0 score of 9.4, critical, with the vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H, and a CVSS 3.1 score of 8.8, high, with CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H. The gap between the two scores comes down to user interaction, which in practice means clicking a link or seeing an ad.
- Affected: every Ray version prior to 2.52.0
- Fixed in: Ray 2.52.0
- Vulnerable endpoints: /api/jobs/ and /api/job_agent/jobs/, on the dashboard's default port 8265
- Browsers that allow the attack: Firefox and Safari; Chrome escapes because of an implementation bug in its own fetch API
- Published on NVD on November 26, 2025, added to the CISA KEV catalog on August 17, 2026
The flaw was found by avilum, of Oligo, and reported with a proof of concept by JLLeitschuh, of Socket. The credit matters here because the fix was not just a targeted patch: version 2.52.0 also introduced token authentication for the dashboard, a feature that simply did not exist before. Worth noting that this authentication ships disabled by default, so updating is not the last step, it is the first one.
The defense that was not a defense: checking the User-Agent
Ray knew that requests coming from a browser were dangerous for an API that executes code. The protection it implemented was to check whether the request's User-Agent header started with the word Mozilla, on the assumption that only browsers send that value and that browsers cannot change it.
# Ray < 2.52.0: a unica barreira contra requisicao vinda de navegador.
def is_browser_request(req: Request) -> bool:
"""Checks if a request is made by a browser like user agent."""
return req.headers["User-Agent"].startswith("Mozilla")
# A premissa: um navegador nao consegue alterar o proprio User-Agent.
# Falsa no Firefox e no Safari, onde a fetch API aceita definir o header.
# No Chrome, um bug de implementacao acabou impedindo a alteracao,
# ou seja, a protecao so funciona por acidente, em um navegador so.The second half of that assumption is that there is a list of headers a page's JavaScript cannot set, the so-called forbidden headers. User-Agent was on that list for a long time, and then it was removed. Firefox and Safari implement the current specification and allow User-Agent to be set on a fetch call. Chrome still blocks it, but because of an implementation defect, not a security decision. A protection that depends on someone else's bug to keep working is not a protection, it is a window of time.
DNS rebinding: the browser as a bridge into the network
Breaking the User-Agent check is not enough on its own, because the browser's same-origin policy stops a site's JavaScript from reading the response from another domain. DNS rebinding exists precisely to get around that: instead of trying to reach another domain, the attacker keeps the same name and changes the IP address it resolves to.
# Sequencia de um DNS rebinding, do ponto de vista do navegador.
1) A vitima abre https://site-do-atacante.exemplo
DNS: site-do-atacante.exemplo -> 203.0.113.10 (TTL de 1 segundo)
2) A pagina carrega e o JavaScript apenas espera o TTL expirar.
3) O navegador resolve o MESMO nome de novo:
DNS: site-do-atacante.exemplo -> 127.0.0.1
4) fetch("http://site-do-atacante.exemplo:8265/api/jobs/", { ... })
Para a politica de mesma origem, continua sendo a mesma origem.
Para a pilha de rede, o pacote agora vai para o servico local.The result is that the victim's browser starts acting as an HTTP client inside the trusted network, taking orders from a script the attacker controls. That holds for Ray on port 8265, but it holds just as well for any admin panel, home router, development database or internal API that trusts the fact that it is only listening on loopback or on the local network. As far as the browser is concerned, loopback was never a trust boundary.
From /api/jobs to arbitrary commands
Once the attacker reaches /api/jobs/ and /api/job_agent/jobs/, the rest is the product working as designed. Ray's jobs API takes an entrypoint field with the command to run on the cluster and runs it. That is what it exists to do. The vulnerability is not in the execution, it is in an arbitrary web page being able to reach that call.
POST /api/jobs/ HTTP/1.1
Host: 127.0.0.1:8265
Content-Type: application/json
User-Agent: laboratorio-interno
{"entrypoint": "id", "runtime_env": {}, "metadata": {}}
# O campo entrypoint e uma linha de comando executada no cluster.
# Aqui usamos 'id' apenas para ilustrar. O ponto do post nao e o
# comando, e o fato de essa requisicao poder partir de uma aba
# de navegador aberta em um site qualquer.In impact terms, the workstation of someone building models tends to be one of the most interesting machines in a company. It holds cloud provider API keys, private repository tokens, data lake credentials, GPU access and, quite often, a local copy of training data. A command executed there is rarely the attacker's end goal, it is the starting point.
RondoDox, ShadowRay 2.0 and CISA's three-day deadline
The timeline of this flaw has an unusual detail. According to Bitsight's analysis, the RondoDox botnet started attempting to exploit CVE-2025-62593 on November 24, 2025, two days before the vulnerability was published on NVD. That is not the usual pattern of reverse engineering a patch after the announcement: whoever ran that botnet was watching the repository, not the bulletin.
On August 17, 2026, CISA added the flaw to the KEV catalog, and under directive BOD 26-04 US federal agencies were given three days to remediate, with a deadline of August 20, 2026. Three days is the window reserved for what is already being exploited consistently, and it is a reasonable priority signal for organizations that are not US federal agencies too.
It is worth separating this flaw from a second story involving the same product that often gets confused with it. The ShadowRay 2.0 campaign, documented by Oligo, exploits CVE-2023-48022, which covers Ray clusters whose jobs API is reachable without authentication and exposed directly on the internet. That CVE is marked as disputed, because Anyscale maintains it is documented product behavior that assumes execution inside a controlled network. The campaign turns exposed clusters into a cryptocurrency mining botnet, and Oligo reports that the number of reachable Ray environments jumped from a few thousand to the hundreds of thousands.
The two stories point to the same lesson from opposite directions. In CVE-2023-48022, the cluster is exposed and the absence of authentication is by design. In CVE-2025-62593, the service is not exposed and is reached anyway, through the browser. In both cases, what breaks is the assumption that the network solves the authentication problem.
What this changes in pentest scope

In the scopes that reach us, the workstation almost never makes the cut, and local development services make it even less often. The reasoning is always the same: it is not exposed. This CVE is a direct counterexample, and it is not the only one. Container orchestration dashboards, Jupyter notebooks, documentation servers, build tools with an HTTP API, debugging proxies, all of it tends to come up on localhost without authentication because it feels like a private environment.
- Update Ray to 2.52.0 or later everywhere, including workstations, which are the direct target of this flaw
- Enable Ray's token authentication, available from 2.52.0 onward but shipped disabled by default
- Inventory the services listening on localhost across development machines and treat each one as reachable by the browser, not as a private environment
- Check whether any Ray cluster is reachable from the internet, the CVE-2023-48022 and ShadowRay 2.0 scenario, which is a separate and more severe problem
- If a development workstation is suspected of compromise, rotate cloud keys, repository tokens and data credentials before calling the case closed
- Put workstations and AI infrastructure explicitly in scope for the next pentest, not as supporting items, but as targets
This post is educational and defense oriented. We do not publish working exploits: the snippets above reproduce code already disclosed in the official advisory and the documented use of the product's API. What we want to make clear is the assumption that failed. When a service's protection is the address it listens on, anyone with a browser inside the network is already on the inside.