DEV Community

Cover image for Plex Servers Are Being Hacked to Mine Crypto. How to Check Yours in 5 Minutes
Alan West
Alan West

Posted on Originally published at blog.authon.dev

Plex Servers Are Being Hacked to Mine Crypto. How to Check Yours in 5 Minutes

If your Plex Media Server is older than 1.43.3.10861 and port 32400 is reachable from the internet, someone may already be running XMRig on it. Attackers started hitting exposed Plex servers with the public Plex2Shell exploit on October 17, 2026, one day after the write-up went live. They don't need a login.

I run Plex at home too, so I went through my own box first. Below are the six checks I ran (version, CPU, one preference, the Codecs folder, logs, outbound connections), what the attack drops, and why I've stopped forwarding 32400.

How Plex2Shell goes from no login to code execution

Plex2Shell is a chain of four CVEs (CVE-2026-96652, -96654, -96655, -96656) published by researcher code-zm. The write-up is worth reading if you like seeing how small mistakes stack up:

  1. /player/timeline checks that an X-Plex-Token header exists, not that it's valid. A protocol field in the subscription becomes a callback URL, so you get an unauthenticated SSRF coming from loopback.
  2. /system/agents/* skips auth for loopback requests. The guard on searchOne does nothing because a @lock decorator throws away its return value, and the identifier goes into an internal URL unencoded.
  3. The bundled TheTVDB agent's GetResultFromNetwork fetches a URL, and the plugin framework attaches the owner's admin token to any URL starting with http://127.0.0.1. That's an unanchored prefix match, so a hostname that merely starts with that string gets the token.
  4. With the owner token, the attacker sets TranscoderH264Options so x264's dump-yuv writes a file into the Codecs directory.
  5. On the next transcode, libavutil.so.58 dlopens every .so in that directory without checking for a signature, a lib prefix or the execute bit, and the code runs as the plex user.

The repo README rates the chain CVSS 3.1 9.8. The individual CVEs scored lower, which is probably why a lot of people ignored Plex's September 1 heads-up about 1.43.2 and earlier.

Plex did respond quickly here. The bug was reported July 27, acknowledged and paid out on August 4, and fixed in 1.43.3.10861. What went wrong was the six weeks in which a lot of servers never got updated.

What's landing on hacked Plex servers

Bored Hacker Blog's honeypot write-up caught the in-the-wild version. The first request hit /player/timeline/subscribe with a protocol value pointing at /system/agents/.../searchOne, from a Python-urllib/3.10 user agent, pulling an attacker URL on an sslip.io hostname. The captured files include:

  • xmrig (Monero miner)
  • a file named docker, served from 217.60.194.116
  • x, a UPX-packed binary, also from 217.60.194.116
  • myawesomeproxy, a proxy tool

The proxy worries me more than the miner, which mostly costs you electricity. The binary itself announces that running it means agreeing to "potential external use of your internet traffic", and the author points out that attackers would love a residential IP proxy for getting into corporate VPN and email accounts. Your connection becomes the source address of someone else's break-in. In the HN thread, one person found a miner config pointing at a MoneroOcean pool, and another mentioned a DDoS node.

Exploiting IPs seen so far: 91.92.40.202, 176.65.139.228, 45.194.92.222.

How to check your Plex server in 5 minutes

Paths below are for a standard Linux package install. Docker users: swap in whatever you mounted at /config, e.g. /config/Library/Application Support/Plex Media Server.

PMS="/var/lib/plexmediaserver/Library/Application Support/Plex Media Server"
Enter fullscreen mode Exit fullscreen mode

1. Plex version

Anything below 1.43.3.10861 is vulnerable.

curl -s http://127.0.0.1:32400/identity
dpkg -l plexmediaserver   # or rpm -q plexmediaserver
Enter fullscreen mode Exit fullscreen mode

2. CPU and plex-owned processes

Miners are lazy and loud. Several HN commenters found theirs because of fan noise, 100% CPU, or buffering streams.

ps -u plex -o pid,ppid,%cpu,etime,cmd --sort=-%cpu | head
docker stats --no-stream        # if Plex is containerised
docker top plex                 # replace with your container name
Enter fullscreen mode Exit fullscreen mode

Plex spawning sh, bash, python, nc or socat is bad. So is anything called xmrig, x, or myawesomeproxy.

3. TranscoderH264Options in Preferences.xml

This setting is where the exploit leaves its fingerprint.

grep -o 'TranscoderH264Options="[^"]*"' "$PMS/Preferences.xml"
Enter fullscreen mode Exit fullscreen mode

If the value contains dump-yuv or stats=, treat the box as compromised.

4. Planted .so files in Codecs

find "$PMS/Codecs" -type f -name '*.so' -newermt 2026-10-16 -ls
find "$PMS/Codecs" -name 'zz[0-9]*.so'
Enter fullscreen mode Exit fullscreen mode

The researcher's hunt script flags zz[0-9]*.so names as a hit. The first command lists every .so touched since the write-up went public. Any of those that didn't come from a Plex update deserves a look.

5. Plex logs

grep -E 'timeline/subscribe.*protocol=|searchOne.*identifier=.*/function|sslip\.io|nip\.io|dump-yuv' \
  "$PMS/Logs/"Plex\ Media\ Server*.log
Enter fullscreen mode Exit fullscreen mode

6. Outbound connections and cron (run as root)

sudo ss -tnp | grep -v 127.0.0.1
sudo crontab -u plex -l
Enter fullscreen mode Exit fullscreen mode

None of the sources report cron persistence yet. I'd still check, because the next crew to pick up this PoC might add it.

If you'd rather not do this by hand, the repo ships detection/hunt/plex2shell-hunt.sh. Its header says nothing is modified, and it wants root for full /proc coverage. It auto-discovers native, /config, snap and Docker installs, and exits 0 (clean), 1 (warnings) or 2 (indicator hits):

./plex2shell-hunt.sh -a "$PMS"
Enter fullscreen mode Exit fullscreen mode

Read it before you run it, like any script off GitHub.

Found something? Don't just kill the process

One of the first comments on HN says it plainly: "It is not sufficient to just remove a running script." I agree. Code ran as plex, and the attacker had your owner token. So:

  • Rebuild the host or container from scratch and restore only your library metadata.
  • Update to 1.43.3.10861 or later before you put it back on the network.
  • Change your Plex password and sign out all authorized devices, since the token was in their hands.
  • Check whether the box was used as a proxy (look for myawesomeproxy and long-lived outbound connections), and look at what else on the same LAN it could reach.

Stop forwarding 32400 to the internet

Patching fixes this bug, and I don't expect it to be the last one. Stage 1 of this chain is a token check that only tests whether the header exists. One HN commenter said the bugs "look like actively made misguided choices." I wouldn't trust that codebase on a raw open port, and I'd say the same about Jellyfin.

Your options, roughly in order of how much I like them:

Option Exposure Works for non-technical family? Catch
Tailscale / WireGuard Nothing public Partly Fire Stick and Android TV are awkward, and it eats the single VPN slot on some devices
Reverse proxy (Caddy/nginx) + Authelia or fail2ban 443 only Yes, for web Plex native apps don't do SSO, so auth in front breaks some clients
Cloudflare Tunnel No open ports Yes Cloudflare's ToS on video streaming is a long-running argument
Port 32400 forwarded Everything Yes You're running this exploit's target config

The obvious counterpoint: Plex's whole sharing model assumes your friends can reach your server, and nobody's mum is installing Tailscale on a Roku. Fair. If you must expose it, at least do this:

  • Restrict egress. This is the best tip in the whole write-up. The honeypot blocked outbound traffic by default, and the author couldn't capture the payloads until they opened it up. Stage 3 needs Plex to call out to an attacker host, and stage 4 needs a download. A media server only needs to talk to plex.tv, metadata providers and your clients.
  • Run the container as a non-root PUID/PGID, with no --privileged and no host networking unless you need it, and no Docker socket mounted.
  • Turn on auto-updates. Synology users, check yours: commenters said the packages there are often behind.
  • Test from outside. Get on mobile data and run curl http://YOUR_PUBLIC_IP:32400/identity. If it answers, the internet can reach you, no matter what the Remote Access page says.

So where does yours stand: is your Plex port forwarded to the internet, or is it behind Tailscale or a reverse proxy? And if you ran the hunt script, did anything come back with exit code 2?

Sources

Top comments (0)