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:
-
/player/timelinechecks that anX-Plex-Tokenheader exists, not that it's valid. Aprotocolfield in the subscription becomes a callback URL, so you get an unauthenticated SSRF coming from loopback. -
/system/agents/*skips auth for loopback requests. The guard onsearchOnedoes nothing because a@lockdecorator throws away its return value, and the identifier goes into an internal URL unencoded. - The bundled TheTVDB agent's
GetResultFromNetworkfetches a URL, and the plugin framework attaches the owner's admin token to any URL starting withhttp://127.0.0.1. That's an unanchored prefix match, so a hostname that merely starts with that string gets the token. - With the owner token, the attacker sets
TranscoderH264Optionsso x264'sdump-yuvwrites a file into the Codecs directory. - On the next transcode,
libavutil.so.58dlopens every.soin that directory without checking for a signature, alibprefix or the execute bit, and the code runs as theplexuser.
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 from217.60.194.116 -
x, a UPX-packed binary, also from217.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"
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
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
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"
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'
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
6. Outbound connections and cron (run as root)
sudo ss -tnp | grep -v 127.0.0.1
sudo crontab -u plex -l
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"
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
myawesomeproxyand 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
--privilegedand 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?
Top comments (0)