Ray-Project Ray — Dashboard/API Code Injection via DNS-Rebinding User-Agent Bypass

CVE-2025-62593 · GHSA-q279-jhrf-cc6v · CISA KEV added 2026-08-17, FCEB due 2026-08-20 · Behavioral / config-driven hunt pack — not a malware family
Threat
CVE-2025-62593 (Ray Dashboard/Jobs API RCE)
Severity
EXPLOITED ITW · CVSS 9.4
Type
CVE / SSRF-style confused deputy / RCE
Access
Network, AC:Low, PR:None, UI:Passive
Version
v0.1 (Draft) · 2026-08-22
Author
HuntPack
Confidence
High — vendor GHSA + gov KEV + 4 independent sources
01

Executive Summary

Ray is an open-source, Python-native distributed compute engine widely used to run AI/ML training and inference clusters. Every Ray head node ships a Dashboard and Jobs API (default port 8265) with no authentication by design — the project's long-standing security model assumed the network around Ray was trusted, and the only defense against a hostile browser reaching that API was a check that the request's User-Agent header started with "Mozilla". That check is trivially bypassed: the fetch spec lets Firefox and Safari override the User-Agent on a request (Chrome has a bug that happens to block this, which is the only reason Chrome users are not equally exposed). Combine that bypass with DNS rebinding — a technique that makes a browser resolve an attacker-registered domain to 127.0.0.1 or another internal address after the same-origin check has already passed — and an attacker-controlled webpage or malicious ad can silently drive a victim's browser to POST a job to /api/jobs/ on any Ray dashboard the victim's machine can reach, with an entrypoint the attacker chooses. Ray executes it. The victim never has to install anything or click "allow" — visiting a page while Ray happens to be running is enough.

The attacker's objective is arbitrary code execution with the privileges of the Ray process — typically a developer's own shell, or the service account running a training/inference cluster — followed by credential, model, and dataset theft, lateral movement into whatever cloud or internal infrastructure that Ray host can reach, and (per the observed "ShadowRay 2.0" activity) GPU-cycle theft via cryptomining on expensive training hardware. CISA added CVE-2025-62593 to KEV on 2026-08-17 citing active exploitation, with a three-day FCEB remediation window (due 2026-08-20) — and per Bitsight reporting cited by multiple outlets, the RondoDox botnet was already probing for this exact flaw two days before the CVE was publicly disclosed on 2025-11-26.

The single highest-value defensive move is not a detection rule — it's closing the precondition: nothing in this attack chain works if the Ray dashboard is bound to loopback only and firewalled from any network the attacker's browser (via the victim) can reach. Everything downstream of that (DNS-rebinding telemetry, unauthenticated-API abuse, anomalous child processes off raylet/gcs_server) is real and worth hunting, but it is defense-in-depth for a bug whose root fix is "don't expose the dashboard, and patch to 2.52.0+ where token auth finally exists."

Defender priority: patch to Ray ≥2.52.0 (2.52.1 preferred) and confirm no Ray dashboard/Jobs API port (8265, plus GCS 6379 and worker ports) is reachable from outside loopback/a private, firewalled subnet — before investing in the behavioral detections in this pack. An internet-exposed, unpatched Ray dashboard is compromised by policy; treat it as such and start incident response, don't wait for a hunt hit.

02

Source Review & Web Hunter Notes

All sources below were fetched on 2026-08-22 and saved verbatim to Ray-CVE-2025-62593-Hunt-sources/ for provenance. No atomic IOC in this pack is sourced from anywhere outside this table.

TierSourceKey findingCarry forward
GovCISA KEV catalog (official JSON feed)Authoritative dateAdded 2026-08-17, dueDate 2026-08-20, BOD 26-04 (not the older BOD 22-01 a secondary article cited), CWE-94 + CWE-352, links to the Ray GHSA and the exact fix commitYes — used for header meta, ticket, and due-date framing
VendorRay Project GHSA-q279-jhrf-cc6vFull technical root cause (User-Agent "Mozilla" check + fetch-spec override on Firefox/Safari), CVSS 4.0 vector 9.4, affected <2.52.0 / fixed 2.52.0, PoC posts JSON to /api/jobs/, fix commit 70e7c72, notes optional token auth added in 2.52.0 (disabled by default)Yes — primary technical source for attack mechanics and remediation
Independent researchResecurity technical write-upSix-stage attack chain, confirms port 8265, exact vulnerable endpoint /api/jobs/, sample malicious request (User-Agent: Other), lists candidate network/log IOCs (all behavioral), notes RondoDox pre-disclosure probing did not successfully bypass the browser checkYes — drove the CQL hypothesis set and the attack-chain table
JournalismThe Hacker NewsConfirms CVSS 9.4, KEV date/deadline, cites RondoDox pre-disclosure activity and a "ShadowRay 2.0" GPU-cryptomining campaign against unpatched instancesPartial — campaign names carried forward as context, not as atomic IOCs
JournalismGBHackersCWE-94/CWE-352 framing, emphasizes impact to credentials/source code/cloud resources/model theft in AI/data-science environmentsPartial — used for impact narrative
JournalismSecurity AffairsKEV addition context; cites Aviatrix research on downstream impact (privilege escalation, lateral movement, C2, exfiltration); this article's "BOD 22-01" reference was superseded by the KEV JSON's own "BOD 26-04" citation — flagged and resolved in favor of the authoritative feedPartial — cross-checked, one factual point corrected against the primary KEV source

Web Hunter decisions: (1) No source — including the vendor advisory — publishes an atomic hash, IP, or C2 domain, because this is a logic/config vulnerability in Ray itself, not a malware family; the IOC table and appendix in this pack are behavioral by design, per the task's own instruction not to fabricate atomic indicators. (2) NVD's CVSS 3.x score (8.8) differs from GitHub's CNA-assigned CVSS 4.0 score (9.4) per Resecurity; this pack uses the CNA/vendor score (9.4) as primary since it's the one GHSA and KEV both track, and notes the NVD figure as a secondary data point. (3) "RondoDox" and "ShadowRay 2.0" are carried forward as named campaigns/context in the exec summary and IOC table, not as verified indicators to detect on directly — they are attributions from secondary journalism, not the primary vendor/gov sources.

03

Hunt Brief & Attack Chain

Hunt hypotheses

  1. (High) A Ray dashboard/GCS process is listening on 8265 (or other Ray ports) on a non-loopback interface reachable by a browser — the precondition for the whole chain.
  2. (High) A shell or interpreter is spawned directly from raylet or gcs_server — the highest-fidelity signal that a job's entrypoint executed attacker code.
  3. (Medium) A Ray-context Python worker process (job execution, titled ray::... at the OS level but recorded by the sensor as a python image) spawns an unexpected shell whose command line references Ray's own session paths.
  4. (Medium) A browser process (Firefox/Safari) opens a direct connection to a local or internal host on port 8265 — the confused-deputy step where the victim's browser becomes the attacker's proxy.
  5. (Medium, investigate-only) The same domain resolves to multiple distinct IP addresses — including loopback/RFC1918 — in a short window: the DNS-rebinding fingerprint.
  6. (Medium) A known GPU-cryptomining binary is spawned from a Ray core process — the "ShadowRay 2.0" post-exploitation pattern.
  7. (Low-Medium) A Ray core process opens an outbound connection to a common cryptomining-pool port, catching a renamed/repacked miner binary that Q6's name list would miss.

Attack chain

StepTelemetryHunt angle
1 · Recon — attacker identifies a reachable Ray instance or simply mass-serves a malicious ad to any visiting browserNone (pre-attack, off-host)Proactive exposure hunt — Q1
2 · Victim visits malicious site/ad while Ray is running locallyBrowser process launch, DNS activityQ5 (DNS pattern), native browser-history review
3 · DNS rebinding resolves the attacker's domain to 127.0.0.1 or an internal Ray host after the same-origin check passesDnsRequestQ5 (flagged unverified field — see card note)
4 · Browser sends a non-Mozilla User-Agent fetch to the dashboard on 8265, bypassing the browser-request checkNetworkConnectIP4 from the browser process; Ray dashboard access logs (not native Falcon telemetry)Q4 + native audit-log hunt (§7)
5 · Attacker's crafted JSON is POSTed to the unauthenticated /api/jobs/ endpoint with a malicious entrypointRay Jobs API access/application log — not present in default Falcon endpoint telemetryNative audit-log hunt (§7) — coverage gap noted in §15
6 · Ray executes the entrypoint; a child process spawns under raylet/gcs_server/the job's Python workerProcessRollup2 / SyntheticProcessRollup2Q2, Q3 — the core, highest-confidence detections in this pack
7 · Post-exploitation — credential/model/data theft, GPU cryptomining, lateral movementProcess, networkQ6, Q7
04

Consolidated IOC Table

No atomic hashes, IPs, or C2 domains have been published for this CVE by any source reviewed (vendor GHSA, CISA KEV, or the four independent write-ups). This is a design/logic flaw in Ray itself, not a malware family with static artifacts — the attacker's DNS-rebinding domain is registered per-campaign and none of the reviewed sources disclosed one. Every row below is a behavioral or configuration indicator; see §10 for the copy-paste blocks.

TypeValueConfidenceActionContextExpiry
PortTCP/8265highhuntDefault Ray Dashboard & Jobs API port — exposure is the precondition for the whole chainn/a (config-based, not perishable)
PortTCP/6379mediumhuntDefault Ray GCS/Redis port — also should never be internet-reachablen/a
Port rangeTCP/10001-19999 (worker ports, cluster-dependent)lowenrichRay worker-to-worker communication range; context only, not a standalone signaln/a
Process nameraylet, gcs_serverhighhuntRay core binaries — parent-of-interest for RCE hunts (Q2)n/a
BehavioralNon-Mozilla User-Agent on a POST to /api/jobs/ or /api/job_agent/jobs/highhuntThe exact browser-check bypass documented in Ray's own advisory and PoC (sample value User-Agent: Other)2027-02-22 (+6mo)
Associated campaignRondoDox (DDoS/IoT botnet)mediumenrichPer Bitsight (cited by secondary journalism), attempted exploitation 2 days before public disclosure; per Resecurity the observed attempt did not successfully bypass Ray's browser check2026-11-22 (+3mo)
Associated campaign"ShadowRay 2.0" (GPU cryptomining)mediumenrichNamed by The Hacker News as exploiting unpatched Ray instances for cryptomining; no atomic IOCs published — hunt via Q6/Q7 behavior instead2026-11-22 (+3mo)
05

Affected Surface & Telemetry Matrix

SurfaceRequired telemetryPriorityGap risk
Linux hosts/servers running Ray <2.52.0 (dev boxes, training/inference nodes)Falcon process + network sensor telemetryHighLow — if Falcon sensor deployed, full coverage
macOS/Windows developer workstations running Ray locally + Firefox/SafariFalcon process + network sensor telemetryHighLow — same as above; Chrome-only shops are lower risk but should still patch
Kubernetes clusters running KubeRay (RayCluster/RayJob CRDs)Falcon Cloud Security / container sensor + node-level telemetryHighMedium-High — container/pod-level process visibility depends on sensor deployment mode; the Jobs API call itself is invisible to endpoint telemetry regardless
Cloud-hosted Ray clusters (AWS/GCP autoscaler-managed)Falcon sensor on cluster nodes + cloud VPC flow logsHighMedium — ephemeral autoscaled nodes may lack sensor coverage at spin-up
Ray dashboard/Jobs API application logsNot native Falcon telemetry — requires a custom/third-party log source ingestMediumHigh — this is the only place the exact bypass (User-Agent + endpoint + entrypoint) is directly visible; see native hunt in §7 and gap noted in §15
Network/perimeter firewall & DNS resolver logsNot Falcon endpoint telemetry — perimeter/DNS infrastructure logsMediumHigh — DNS-rebinding detection is fundamentally a DNS-resolver-side problem; Q5 is a best-effort proxy from endpoint DNS telemetry only
06

ATT&CK Mapping

TacticTechnique IDTechnique nameObserved behavior
Initial AccessT1189Drive-by CompromiseVictim's browser triggers exploitation merely by loading a malicious page/ad while Ray runs locally — no click, download, or install required
Initial Access / ExecutionT1210Exploitation of Remote ServicesUnauthenticated Ray Jobs API (/api/jobs/) accepts an attacker-supplied entrypoint via the browser-mediated confused-deputy path
ExecutionT1059Command and Scripting InterpreterJob entrypoint executes as a subprocess of the Ray runtime with the privileges of the Ray process
Defense Evasion (no exact ATT&CK ID)CAPEC-664 (reference only)DNS RebindingAttacker domain re-resolves to loopback/internal address after the browser's same-origin check has already passed; ATT&CK has no discrete technique for DNS rebinding itself — closest formal mapping is CAPEC-664
Credential AccessT1552Unsecured CredentialsRay processes routinely hold cloud/API credentials, S3/GCS keys, and internal service tokens in environment or config reachable once code executes
CollectionT1005Data from Local SystemTraining data, model artifacts, and source code accessible to the compromised Ray process
ImpactT1496Resource Hijacking"ShadowRay 2.0"-style GPU cryptomining deployed on compromised training/inference hardware
07

Native Audit-Log Hunts

These checks cover the parts of the attack chain (steps 4-5) that Falcon endpoint telemetry does not natively see — the Jobs API call itself only exists in Ray's own dashboard/API access logs.

1. Ray dashboard/API access-log review (if ingested to any log platform)

If the Ray dashboard's HTTP access log is captured anywhere (reverse proxy, application log shipper, or a custom LogScale ingest), grep/search for:

POST /api/jobs/ or POST /api/job_agent/jobs/
User-Agent NOT starting with "Mozilla"    // the exact bypass condition per Ray's own advisory
                                            // sample observed value in the vendor PoC: "User-Agent: Other"

Any hit is a near-certain exploitation attempt — the legitimate Ray CLI/SDK does not send browser-style requests to this endpoint from an external origin.

2. Ray version & dashboard-bind configuration audit

Run on every host known or suspected to run Ray (fleet inventory, package manager, or container image scan):

pip show ray 2>/dev/null | grep -i version
ray --version
ps aux | grep -E "raylet|gcs_server|dashboard" | grep -v grep
# Confirm the dashboard is NOT bound to 0.0.0.0 — the flag that widens exposure:
ps aux | grep -- "--dashboard-host" 

Flag any result showing Ray <2.52.0, or a --dashboard-host value other than 127.0.0.1/localhost on a host with any network reachability beyond a fully trusted, segmented cluster subnet.

3. Ray token-authentication status audit (post-patch verification)

Ray 2.52.0+ ships an optional, disabled-by-default token-auth feature. Confirm it is actually enabled after patching — an unpatched-then-patched host that never turned auth on is still relying on network exposure alone:

ray status
env | grep -i RAY_AUTH   # or check the equivalent startup flag/config per Ray 2.52+ docs
08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first — every "Open in Falcon" button below uses this selection.
Q1 · Ray Dashboard/GCS Exposed on a Non-Loopback Interface (port 8265)
CONF HIGHFP MEDCOST LOW

Looks for: a listening socket on Ray's default dashboard/Jobs API port bound to any address other than loopback — the precondition the entire attack chain requires. FP: intentional multi-node Ray clusters legitimately bind the dashboard to a routable interface on a trusted, segmented subnet; that is expected and should be excluded by host allowlist, not treated as a finding on its own.

// HUNT: Ray Dashboard/GCS listening on non-loopback interface (port 8265)
// MITRE: T1190
// CONF: high  FP: medium  COST: low | REQUIRES: NetworkListenIP4
// FALSE POSITIVES: legitimate multi-node Ray clusters bound to a private, firewalled subnet
// TUNING: exclude known Ray head-node ComputerName values on trusted, segmented cluster subnets
// LOOKBACK: 7d (set via console time picker)
#event_simpleName=NetworkListenIP4
| LocalPort=8265
| LocalAddressIP4!="127.0.0.1"
| table([ComputerName, aid, LocalAddressIP4, LocalPort, ContextBaseFileName, ContextProcessId_decimal])
Q2 · Shell/Interpreter Spawned Directly From raylet or gcs_server
CONF HIGHFP LOWCOST LOW

Looks for: a shell or scripting interpreter whose direct parent is Ray's own core binary — raylet or gcs_server do not normally spawn shells during legitimate cluster operation. This is the highest-fidelity, IOA-eligible detection in the pack. FP: low — these are Ray's internal orchestration binaries, not general-purpose parents.

// HUNT: Shell/interpreter spawned directly from raylet or gcs_server
// MITRE: T1210, T1059
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
// FALSE POSITIVES: none expected under normal Ray cluster operation
// LOOKBACK: 7d (set via console time picker)
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ParentBaseFileName=/^(raylet|gcs_server)(\.exe)?$/i
| FileName=/^(cmd|powershell|pwsh|sh|bash|dash|zsh|nc|ncat|curl|wget|python3?|perl|ruby|osascript)(\.exe)?$/i
| table([ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine, TargetProcessId_decimal, ParentProcessId_decimal])
Q3 · Ray Worker (Python) Process Spawning an Unexpected Shell With a Ray-Session Reference
CONF MEDFP MEDCOST LOW

Looks for: Ray job workers are OS-titled ray::IDLE/ray::<task> via setproctitle, but the sensor records the underlying binary as python/python3. This catches a shell spawned by that python parent where the child's own command line still carries a Ray session-path fingerprint (Ray writes runtime state under ray/session_latest). FP: medium — general-purpose python-spawns-shell is common; the ray substring requirement narrows it but validate against your own ML pipeline tooling.

// HUNT: Ray worker (python) process spawning shell referencing a Ray session path
// MITRE: T1210, T1059
// CONF: medium  FP: medium  COST: low | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
// FALSE POSITIVES: legitimate ML pipeline/orchestration scripts that shell out and reference Ray paths
// TUNING: exclude known CI/ML orchestration hosts and service accounts that legitimately shell out from Ray jobs; validate in tenant
// LOOKBACK: 7d (set via console time picker)
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ParentBaseFileName=/^python3?(\.exe)?$/i
| FileName=/^(cmd|powershell|pwsh|sh|bash|dash|zsh|nc|ncat|socat|python3?|perl|ruby|osascript)(\.exe)?$/i
| CommandLine=*ray*
| table([ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine, TargetProcessId_decimal])
Q4 · Browser Process Connecting Directly to Local/Internal Ray Dashboard Port
CONF MEDFP HIGHCOST LOW

Looks for: Firefox/Safari (the two vulnerable browsers per the vendor advisory) opening a connection to port 8265 — the confused-deputy step. FP: high — a developer legitimately opening http://localhost:8265 in their own browser to view the dashboard is completely normal and indistinguishable from this at the network layer alone; this query is a candidate-generation feed for manual triage, not a standalone alert. Cross-reference hits against Q5's DNS pattern and against whether the destination was reached via a known-good bookmark/direct navigation vs. an ad/redirect chain (requires browser history, outside Falcon's scope). ⚠ ContextBaseFileName values for browser subprocesses vary by OS/version (e.g. macOS WebKit content-process naming) — validate the exact process names your fleet reports in tenant before tuning thresholds.

// HUNT: Browser process connecting to local/internal Ray dashboard port 8265
// MITRE: T1189, T1210
// CONF: medium  FP: high  COST: low | REQUIRES: NetworkConnectIP4
// FALSE POSITIVES: developers legitimately viewing their own Ray dashboard UI in a browser
// TUNING: cross-reference against Q5 DNS-rebinding candidates before alerting; exclude known developer workstations with an approved, documented reason to browse to their own dashboard
// LOOKBACK: 7d (set via console time picker)
#event_simpleName=NetworkConnectIP4
| RemotePort=8265
| ContextBaseFileName=/^(firefox(\.exe)?|safari|com\.apple\.webkit\.webcontent|plugin-container)$/i
| table([ComputerName, aid, UserName, ContextBaseFileName, RemoteAddressIP4, RemotePort, LocalAddressIP4])
Q5 · DNS-Rebinding Signature — Domain Re-Resolving to Multiple Distinct IPs in a Short Window (investigate-only)
CONF MEDFP HIGHCOST MED

Looks for: a ranked list of domains by query volume in a short window, with their resolved IPs collected for manual eyeballing — DNS rebinding shows up as the same domain resolving to a public IP and then, moments later, to 127.0.0.1 or an RFC1918 address, once the browser's same-origin check has already passed. FP: high — legitimate CDNs, load balancers, and failover DNS also rotate answers; this is a candidate-generation query for an analyst, not an auto-alert. ⚠ Field unverified — validate in tenant: the resolved-IP field on DnsRequest is written here as IP4Records; this is not confirmed against this pipeline's own Falcon data-model reference and must be checked against your tenant's actual DnsRequest schema before relying on it — if the field name differs, the query will parse but silently return nothing.

// HUNT: Same domain resolving to multiple distinct IPs incl. loopback/RFC1918 (DNS-rebinding fingerprint)
// MITRE: CAPEC-664 (no exact ATT&CK technique for DNS rebinding)
// CONF: medium  FP: high  COST: medium | REQUIRES: DnsRequest
// FALSE POSITIVES: CDNs, load balancers, and DNS-based failover legitimately rotate resolved IPs
// TUNING: manually review resolved_ips for a mix of a public IP and a loopback/RFC1918 IP for the SAME domain in the SAME short window; a single stable IP list is not a hit
// ⚠ Field unverified — validate in tenant: IP4Records
// LOOKBACK: 15m (short window — rebinding relies on rapid re-resolution; a long window dilutes the signal)
#event_simpleName=DnsRequest
| groupBy([DomainName], function=([count(as=query_count), collect(IP4Records)]), limit=max)
| rename(field=IP4Records, as=resolved_ips)
| sort(query_count, order=desc)
| table([DomainName, query_count, resolved_ips])
Q6 · Known GPU-Cryptomining Binary Spawned From a Ray Core Process ("ShadowRay 2.0" Pattern)
CONF MEDFP LOWCOST LOW

Looks for: post-exploitation cryptomining, the pattern named "ShadowRay 2.0" in press coverage of this CVE, where compromised GPU-equipped Ray training nodes are repurposed for mining. FP: low — these binary names have no legitimate reason to run under a Ray process.

// HUNT: Known cryptomining binary spawned from raylet/gcs_server/Ray worker python
// MITRE: T1496
// CONF: medium  FP: low  COST: low | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
// FALSE POSITIVES: none expected; a renamed miner binary will evade this — see Q7 for a complementary network-based check
// LOOKBACK: 7d (set via console time picker)
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ParentBaseFileName=/^(raylet|gcs_server|python3?)(\.exe)?$/i
| FileName=/^(xmrig|ccminer|nbminer|t-rex|phoenixminer|lolminer|nanominer|ethminer|kinsing|kswapd0)(\.exe)?$/i
| table([ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine, SHA256HashData])
Q7 · Ray Core Process Connecting to a Common Cryptomining-Pool Port
CONF LOWFP HIGHCOST LOW

Looks for: a complementary, network-based catch for Q6 against a renamed/repacked miner binary — legitimate mining pools listen on a well-known set of ports. FP: high — several of these ports (8080, 9999) are used by unrelated legitimate services; treat as a low-confidence enrichment signal only, correlated with Q6 or unusual sustained outbound traffic volume/CPU-GPU utilization, neither of which is available via this query alone.

// HUNT: Ray core process connecting to a known cryptomining-pool port
// MITRE: T1496
// CONF: low  FP: high  COST: low | REQUIRES: NetworkConnectIP4
// FALSE POSITIVES: legitimate services on 8080/9999/etc.; this is an enrichment signal, not a standalone alert
// TUNING: correlate with Q6 hits or sustained high outbound byte-count before triaging as a positive; exclude known internal service ports in this range
// LOOKBACK: 7d (set via console time picker)
#event_simpleName=NetworkConnectIP4
| ContextBaseFileName=/^(raylet|gcs_server|python3?)(\.exe)?$/i
| RemotePort=/^(3333|4444|5555|7777|14444|14433)$/
| table([ComputerName, aid, ContextBaseFileName, RemoteAddressIP4, RemotePort])
09

CrowdStrike Custom IOA Recommendations

IOA nameSource queryPatternExclusionsDeployment path
Shell Spawned From Ray Core Process (raylet/gcs_server)Q2Parent image = raylet or gcs_server; child image matches shell/interpreter allowlistNone expected in normal operation — monitor only, IOA-eligiblePromote directly to a blocking or high-severity-alerting Custom IOA; this is the pack's highest-confidence, lowest-FP signal
Known Cryptominer Spawned From Ray ProcessQ6Parent image = Ray core/worker; child image matches known-miner binary-name listNone expected; supplement with hash-based detection where possible since names are trivially changedPromote to a Custom IOA; pair with Falcon's built-in cryptomining detections if licensed for that module
Ray Dashboard Bound Beyond Loopback (Q1)Q1State-based network exposure, not an event-driven behaviorKnown, documented multi-node cluster head nodes on trusted subnetsKeep as a scheduled hunt/dashboard query, not an IOA — this is a config-audit signal, better suited to periodic scheduled search than real-time event matching
Browser-to-Ray-Dashboard Connection (Q4) / DNS-Rebinding Candidate (Q5)Q4, Q5n/an/aInvestigate-only — FP profile is too high for IOA promotion without a browser-history/DNS-resolver correlation layer this pack does not have access to
10

Machine-Readable IOC Appendix

This threat has no published atomic IOCs — the CSV block below intentionally carries only REPLACE_WITH_… placeholders and behavioral entries. Populate the placeholders only if your own incident response turns up a campaign-specific artifact (e.g., an attacker DNS-rebinding domain observed in your own logs); do not invent values to fill the block.

Falcon IOC Management CSVbulk import
type,value,action,severity,expiration,description,tags
domain,REPLACE_WITH_OBSERVED_REBINDING_DOMAIN,detect,high,2027-02-22,CVE-2025-62593 DNS-rebinding domain observed in your own IR,campaign:Ray-CVE-2025-62593
ipv4,REPLACE_WITH_OBSERVED_ATTACKER_IP,detect,high,2027-02-22,CVE-2025-62593 attacker infrastructure observed in your own IR,campaign:Ray-CVE-2025-62593
sha256,REPLACE_WITH_OBSERVED_PAYLOAD_HASH,detect,high,2027-02-22,Payload dropped via CVE-2025-62593 job entrypoint observed in your own IR,campaign:Ray-CVE-2025-62593
Behavioral Signaturesprocess / network patterns
ParentImage: raylet | gcs_server  ->  Child: shell/interpreter (cmd, powershell, sh, bash, python)
Listening socket: 0.0.0.0:8265 or non-loopback bind of the Ray dashboard/Jobs API
HTTP: POST /api/jobs/ or /api/job_agent/jobs/ with User-Agent NOT starting with "Mozilla"
DNS: same domain resolving to a public IP then to 127.0.0.1/RFC1918 within a short window
Process: xmrig/ccminer/nbminer/t-rex/phoenixminer/lolminer/nanominer/ethminer/kinsing spawned from raylet/gcs_server/python
Named Tooling / Campaigns (context only)not atomic indicators
RondoDox botnet - attempted pre-disclosure exploitation of CVE-2025-62593 (per Bitsight/Resecurity); did not
  successfully bypass Ray's browser check per Resecurity's analysis. No atomic RondoDox IOC in this pack.
"ShadowRay 2.0" - press-coined name for GPU-cryptomining campaigns against unpatched, exposed Ray instances.
  No atomic indicators published; hunt via Q6/Q7 behavior.
Patch / Exposure Audit Checklistconfig verification
[ ] Ray version >= 2.52.0 (2.52.1 preferred) on every host/image/cluster
[ ] Dashboard NOT bound to 0.0.0.0 -- confirm --dashboard-host is 127.0.0.1 or a firewalled private address
[ ] Port 8265 (and 6379 GCS) not reachable from any untrusted network or the public internet
[ ] Ray 2.52+ token authentication enabled (it ships disabled by default)
[ ] KubeRay dashboard Service type is ClusterIP, not LoadBalancer/NodePort, with a NetworkPolicy restricting ingress
[ ] Credentials/tokens on any historically-exposed Ray host rotated
11

Detection Validation Gates

GateCheckStatus before deployment
Telemetry readyConfirm ProcessRollup2/SyntheticProcessRollup2, NetworkConnectIP4, NetworkListenIP4, and DnsRequest are flowing for every host in scopeRequired before Q1-Q4, Q6-Q7 are trustworthy
Benign baselineRun Q1 and Q4 first in investigate mode against known-good Ray dev hosts to characterize normal exposure/browsing patterns before tuning exclusionsRequired — both have real FP sources documented above
Field verificationConfirm the IP4Records field name on DnsRequest in your own tenant before relying on Q5 (flagged unverified in the query card)Required before Q5 is trusted
Positive testWhere safe, replicate the vendor PoC (POST a benign entrypoint to a lab Ray instance from a script with a non-Mozilla User-Agent) to confirm Q2/Q3 fire on the resulting child processRecommended in an isolated lab, never against production
PromotionOnly promote Q2 and Q6 to blocking/high-severity IOAs (see §9); keep Q1, Q3, Q4, Q5, Q7 as scheduled hunts pending FP tuningGate before §9 IOAs go live
12

Hardening — Tiered

Immediate — this week

Upgrade Ray to ≥2.52.0 (2.52.1 preferred) on every host, container image, and cluster template. M1050 Update Software. This is the vendor fix commit (70e7c72) that corrects the browser-request check. Verify: pip show ray | grep -i version on a sample of the fleet.

Bind the Ray dashboard/GCS to loopback or a private, firewalled interface — never 0.0.0.0 on anything internet-reachable. M1030 Network Segmentation / M1035 Limit Access to Resource Over Network. Verify: run Q1 (§8) and confirm zero non-loopback listeners outside a documented, trusted cluster subnet.

Firewall port 8265 (and 6379/GCS, plus the worker port range) from any untrusted network at the host and network layer. M1037 Filter Network Traffic. Verify: external port scan / cloud security-group audit.

Enable Ray 2.52+'s token authentication — it ships disabled by default, so patching alone does not turn it on. ⚠ best-practice, no formal CIS/vendor-baseline benchmark exists for Ray specifically — this is the vendor's own documented hardening recommendation in the GHSA. Verify: §7's token-auth status audit.

Near term — 1 to 4 weeks

KubeRay clusters: set the dashboard Service type to ClusterIP (never LoadBalancer/NodePort) and apply a Kubernetes NetworkPolicy restricting ingress to the dashboard port to trusted namespaces only. M1030 Network Segmentation, per CIS Kubernetes Benchmark's NetworkPolicy guidance. Verify: kubectl get networkpolicy -n <ray-namespace>.

Standardize developer browser policy toward Chromium-based browsers where feasible, or enforce Private Network Access / Local Network Access enforcement where the browser vendor supports it — Chrome's PNA behavior is the reason Chrome-only users are not equally exposed. ⚠ best-practice, no formal benchmark — Firefox does not yet enforce PNA per the sources reviewed; this reduces but does not eliminate risk. Verify: browser enterprise-policy configuration audit.

Deploy the CQL detections in §8 as scheduled searches, working through the validation gates in §11 before promoting Q2/Q6 to IOAs.

Rotate credentials/tokens on any host with historical internet exposure of the Ray dashboard, treating exposure as presumed compromise pending forensic review. Best practice — general credential hygiene, no single formal citation.

Strategic — 1 to 3 months

Formalize an internal policy requiring network-segmented, authenticated Ray deployment as a standard, not an opt-in — this bug exists because the ecosystem defaulted to "trusted network" as its only control for years. M1030 + M1035, defense-in-depth framing.

Establish quarterly exposure scanning of dashboard/management ports (8265, 6379, and equivalents for other ML-tooling frameworks) across the cloud and dev fleet, not just at patch time. M1016 Vulnerability Scanning.

Architecture review of any other internally-trusted, unauthenticated-by-default dev tooling exposed to developer workstations running browsers — this vulnerability class (browser as confused deputy via DNS rebinding into a "localhost-trusted" service) generalizes beyond Ray.

13

Deployable Playbooks

Playbook 1 — Upgrade Ray and verify version (Linux/macOS)

Prerequisites: pip/conda access to the target environment; a maintenance window if Ray is actively serving production jobs. Reboot required: No — restart the Ray process/cluster, not the host. Rollback: pin back to the prior version with pip install ray==<previous_version> if the upgrade breaks a dependency; keep the prior requirements.txt/lockfile on hand before upgrading.

pip install -U "ray>=2.52.0"
ray --version
# Restart any running cluster so the new binary takes effect:
ray stop
ray start --head   # or your cluster's normal start invocation

Playbook 2 — Bind dashboard to loopback and enable token auth

Prerequisites: Ray ≥2.52.0 already installed (Playbook 1). Know whether any legitimate remote user needs dashboard access (if so, front it with an authenticated reverse proxy/VPN instead of a public bind). Reboot required: No — Ray process restart only. Rollback: revert the start flags to the prior invocation; if a documented remote-access need existed, restore the previous reverse-proxy config rather than re-exposing the raw port.

# Bind dashboard to loopback only (default in recent Ray, but verify explicitly):
ray start --head --dashboard-host=127.0.0.1

# Enable token authentication (Ray 2.52+, disabled by default -- exact flag/env
# var per your installed Ray minor version's release notes; verify against
# `ray start --help` on your installed version before scripting this into CI):
# RAY_ENABLE_AUTH=1 ray start --head --dashboard-host=127.0.0.1
ray status

Playbook 3 — Host/network firewall rule blocking external access to Ray ports

Prerequisites: sudo/root on the host, or cloud security-group edit access; confirm no legitimate cross-host cluster traffic will be blocked (check worker port range for multi-node clusters first). Reboot required: No. Rollback: remove the added rule (ufw delete deny ... / revert the security-group change) to restore prior connectivity.

# Linux host firewall (ufw example) -- deny 8265/6379 from anything outside a trusted subnet:
sudo ufw deny from any to any port 8265 proto tcp
sudo ufw allow from 10.0.0.0/8 to any port 8265 proto tcp
sudo ufw deny from any to any port 6379 proto tcp
sudo ufw allow from 10.0.0.0/8 to any port 6379 proto tcp
sudo ufw reload

# Cloud security group (AWS CLI example) -- remove any 0.0.0.0/0 ingress on 8265/6379:
aws ec2 revoke-security-group-ingress --group-id sg-REPLACE_WITH_SG_ID --protocol tcp --port 8265 --cidr 0.0.0.0/0
aws ec2 revoke-security-group-ingress --group-id sg-REPLACE_WITH_SG_ID --protocol tcp --port 6379 --cidr 0.0.0.0/0

Playbook 4 — Kubernetes NetworkPolicy restricting KubeRay dashboard ingress

Prerequisites: a CNI plugin that enforces NetworkPolicy (Calico, Cilium, etc. -- confirm before relying on this, some default CNIs silently no-op policies); cluster-admin or namespace-admin access. Reboot required: No. Rollback: kubectl delete networkpolicy ray-dashboard-restrict -n <namespace> to remove the policy and restore prior (unrestricted) ingress.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ray-dashboard-restrict
  namespace: REPLACE_WITH_RAY_NAMESPACE
spec:
  podSelector:
    matchLabels:
      ray.io/node-type: head
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              trusted-ray-client: "true"
      ports:
        - protocol: TCP
          port: 8265

Playbook 5 — Post-hardening verification spot-check (CQL)

Prerequisites: Playbooks 1-4 applied; Falcon sensor deployed and reporting for the target hosts. Reboot required: No -- this is a read-only verification query. Rollback: none required -- it changes nothing.

// HUNT: Post-hardening spot-check -- confirm Q1's non-loopback exposure is gone
#event_simpleName=NetworkListenIP4
| LocalPort=8265
| LocalAddressIP4!="127.0.0.1"
| table([ComputerName, aid, LocalAddressIP4, LocalPort])
// Expected result after Playbooks 1-3: zero rows outside documented, trusted cluster subnets.
14

Containment Runbook

PhaseActionsOwnerEvidence to preserve
IsolateNetwork-isolate the affected Ray host (endpoint containment via Falcon, or remove from the load balancer/cluster); do not simply restart the Ray process, which destroys process-tree evidenceIR / SOC on-callFalcon process tree for the suspect job's entrypoint; any Ray dashboard access logs covering the incident window
EradicateKill the malicious child process and any persistence it established; patch to Ray ≥2.52.0 and apply Playbooks 2-3 before returning the host to service; rotate every credential/token the Ray process had access to (cloud keys, S3/GCS creds, internal service tokens)IR + platform/infra ownerHash and preserve any dropped payload before deletion; document exact credential set rotated
RecoverRedeploy from a known-good, patched image/config rather than trusting the compromised host's current state; re-enable with hardened config (loopback bind, firewall, token auth) from day one; re-add to the cluster only after passing Playbook 5's verification queryPlatform/infra ownerRedeployment record; Playbook 5 query result showing zero exposure
Post-incidentSweep the rest of the fleet for the same exposure pattern (Q1) and the same process-spawn pattern (Q2/Q3) across the retention window; update the exposure-audit checklist cadence per §12's strategic tierThreat hunting / detection engineeringFleet-wide Q1/Q2/Q3 sweep results
15

Detection Coverage Map

Technique / Chain stepBehaviorCQLIOACoverage
Step 1 — Recon / preconditionRay dashboard exposed on non-loopback interfaceQ1No (scheduled hunt only)Partial
Step 2-3 — DNS rebindingDomain re-resolving to loopback/RFC1918Q5 (unverified field)NoGAP — DNS-rebinding detection is fundamentally resolver-side, not endpoint-side; Q5 is best-effort only
Step 4 — Browser bypasses UA checkBrowser connects to local Ray dashboard portQ4NoPartial — high FP without browser-history correlation this pack lacks
Step 5 — Malicious job submitted to Jobs APINon-Mozilla UA POST to /api/jobs/None — not native Falcon telemetryNoGAP — requires Ray dashboard access-log ingest; see native hunt §7
Step 6 — RCE via job entrypointShell/interpreter spawned from raylet/gcs_server/Ray workerQ2, Q3Q2 (recommended)Good — highest-confidence coverage in the pack
Step 7 — Post-exploitation (cryptomining)Known miner binary or mining-pool connection from Ray processQ6, Q7Q6 (recommended)Good for named binaries; Partial for renamed/unknown miners
Step 7 — Post-exploitation (credential/data theft, lateral movement)Credential access, data staging from compromised Ray hostNone — generalized to your existing credential-access/exfil detectionsNoGAP — out of scope for this pack; route to existing credential-theft/exfil detection coverage

Validation gates: see §11 for the full gate table. Summary — confirm telemetry coverage and baseline FP before enabling any query; verify the flagged IP4Records field on Q5 in your own tenant; only Q2 and Q6 are recommended for IOA promotion at this time.

16

Hunt Summary Ticket

TITLE: Hunt — Ray-Project Ray Dashboard/API RCE via DNS-Rebinding UA Bypass (CVE-2025-62593)
SEVERITY: Critical (CVSS 9.4, CISA KEV, actively exploited)
SCOPE: All hosts/images/clusters running Ray <2.52.0; all developer workstations running Ray + Firefox/Safari;
       all KubeRay/cloud-hosted Ray clusters
HYPOTHESIS: An attacker-controlled webpage/ad drives a victim browser, via DNS rebinding + User-Agent bypass,
       to submit a malicious job to Ray's unauthenticated Jobs API, achieving RCE as the Ray process.
QUERIES: Q1 (exposure) / Q2 (raylet-gcs shell spawn, high-conf) / Q3 (worker python shell spawn) /
       Q4 (browser-to-dashboard connection) / Q5 (DNS-rebinding candidate, unverified field) /
       Q6 (known miner spawn) / Q7 (mining-pool port connection)
DO FIRST: Confirm patch status (Ray >=2.52.0) and dashboard exposure (Q1) fleet-wide -- this closes the
       precondition regardless of hunt results. Then run Q2 and Q6 as the highest-confidence sweeps.
FINDINGS: [populate after hunt execution]
GAPS: DNS-rebinding detection (Step 2-3) and Jobs-API abuse detection (Step 5) both lack native Falcon
       telemetry coverage -- see Coverage Map (S15) and native audit-log hunts (S7).
ACTIONS: Patch, firewall, enable token auth (S12); deploy Q2/Q6 as IOAs after S11 validation gates pass.
OWNER: [assign]
VERSION: v0.1 · 2026-08-22
17

Changelog

v0.12026-08-22Initial draft — full pipeline run (web-hunter-v2 → threat-hunter-v2 → crowdstrike-logscale-v3 → alert-builder-v2 → threat-hardening-v2 → review-v2) against CVE-2025-62593. 7 CQL queries, 2 IOA candidates, full hardening/playbook/containment sections. No atomic IOCs published for this CVE — pack ships behavioral detections only.
18

References

TierSourceUsed forAccess date
GovCISA KEV Catalog — CVE-2025-62593Authoritative dateAdded/dueDate/BOD, header meta, ticket2026-08-22
VendorRay Project GHSA-q279-jhrf-cc6vRoot-cause technical detail, PoC, CVSS vector, fix commit, remediation2026-08-22
Independent researchResecurity — Ray CVE-2025-62593 technical write-upAttack-chain staging, endpoint/port detail, candidate IOC list2026-08-22
JournalismThe Hacker News — CISA Flags Actively Exploited Ray FlawKEV context, RondoDox/ShadowRay 2.0 campaign naming2026-08-22
JournalismGBHackers — CISA Warns of Active Exploitation of Ray-Project Ray Code Injection VulnerabilityImpact narrative, mitigation checklist framing2026-08-22
JournalismSecurity Affairs — U.S. CISA adds a Ray-Project Ray flaw to its KEV catalogKEV addition context; one factual point (BOD number) corrected against primary source2026-08-22