What the Plex2Shell chain contains
According to BleepingComputer, which relays the CISA alert, the chain strings together four Plex Media Server flaws. The first, CVE-2026-96652, is a server-side request forgery (SSRF) on the /player/timeline endpoint, reachable without authentication: a stranger can make your server send requests. The other three, CVE-2026-96654, CVE-2026-96655 and CVE-2026-96656, extend the attack to arbitrary file writes in the transcoder parameters, which can lead to code execution. The critical score of 9.8 is the one the researcher gives to the whole chain, not an official score assigned to each flaw. The details have been public since October 2026, exploitation is reported from 17 October 2026, and CISA set 23 October 2026 as the remediation deadline for US federal agencies.
The four flaws and the fix at a glance
Scroll the table
| Reference | Nature | Role in the chain |
|---|---|---|
| CVE-2026-96652 | SSRF on `/player/timeline`, unauthenticated | Entry point: no account required |
| CVE-2026-96654 | URL injection in `searchOne` | Lets an attacker call other plugins' functions |
| CVE-2026-96655 | Authenticated SSRF in the transcoder endpoint | Widens the reach of internal requests |
| CVE-2026-96656 | Arbitrary file write through transcoder parameters | Last link: code execution possible |
| Fixed version | Plex Media Server 1.43.3.10861 or later | Every earlier version is vulnerable |
| Score of 9.8 | Given to the whole chain by the researcher | Not an official score for each flaw |
"My Plex is up to date": why that is not enough
Updating closes the flaws, not the door, and removes nothing an intruder has already left behind. Three cases come up. The server was fixed after the details were published: if it was exposed and vulnerable in the meantime, it may have been compromised before your update. The server was never fixed, because Plex on Linux does not update itself and a container keeps the image it started with. Or the server is up to date, but port 32400 is still open to everyone when only your family uses it. So there are three steps: check the version, reduce exposure, look for traces.
Reading the installed version and updating, by environment
Scroll the table
| Environment | Read the installed version | Update |
|---|---|---|
| Debian / Ubuntu | `dpkg -s plexmediaserver | grep Version` | `sudo apt update && sudo apt install --only-upgrade plexmediaserver` |
| RHEL / AlmaLinux | `rpm -q plexmediaserver` | `sudo dnf upgrade plexmediaserver` if the Plex repository is configured, otherwise the .rpm package from the official download page |
| Docker | `version` attribute of `curl -s http://127.0.0.1:32400/identity` if the port is published | `docker pull plexinc/pms-docker` + `docker compose up -d --force-recreate` |
| All cases | `curl -s http://127.0.0.1:32400/identity` returns a short XML with the `version` attribute | Then restart: `sudo systemctl restart plexmediaserver` |
Port 32400: what must stay closed
Plex listens on port 32400 by default. On a VPS the firewall is yours: with no rule, the port is reachable from the Internet, and a Docker container writes its own rules that bypass ufw. The command ss -tlnp | grep 32400 shows whether Plex listens on all interfaces (0.0.0.0 or *) or only on 127.0.0.1. It does not prove the port is reachable from outside, since the firewall may filter it: the real test runs from another machine. With a dedicated IPv4 address, as on a VPS, this is the first check to make.
Close direct exposure in seven steps
Update first
Apply the command for your environment from the table above, then
sudo systemctl restart plexmediaserver. Then check the version withcurl -s http://127.0.0.1:32400/identity: theversionattribute must show 1.43.3.10861 or a newer version.Measure the exposure
ss -tlnp | grep 32400
From another machine:nc -vz 203.0.113.10 32400(replace the example address with your VPS's IPv4). A successful connection means Plex is exposed.Turn off direct remote access in Plex
In the server settings, disable direct remote access. Plex then stops trying to make the port reachable from the Internet.
Close the port in the firewall
sudo ufw allow OpenSSHsudo ufw deny 32400/tcpsudo ufw enablesudo ufw status numbered
Allow SSH before enablingufw, or you lock yourself out.Under Docker, publish on the loopback
In the Compose file, replace the published port with
127.0.0.1:32400:32400, thendocker compose up -d --force-recreate. Aufwrule is not enough here: Docker goes first.Check again from outside
nc -vz 203.0.113.10 32400
The connection must now fail or time out. If it still succeeds, the firewall is not what filters, or Docker still publishes the port.Reconnect legitimate access
The next two sections describe an authenticated reverse proxy for the browser and a VPN for the apps. Choose before reopening anything.
Reverse proxy or VPN: which to choose
Both close port 32400 to the whole world, but they do not serve the same clients. A reverse proxy with authentication protects the Plex web interface in a browser, with TLS in front. Plex apps on TVs and phones cannot answer HTTP Basic authentication: behind that proxy, they fail. For them the VPN is the clean route: after sudo apt install wireguard and the peer configuration, the rule sudo ufw allow in on wg0 to any port 32400 proto tcp opens Plex only to the tunnel interface. Remember that the VPN covers every client, and the proxy only the browser.
A testable example: nginx with authentication
Install nginx and the password tool
Debian / Ubuntu:
sudo apt install nginx apache2-utils
RHEL / AlmaLinux:sudo dnf install nginx httpd-toolsCreate a user
sudo htpasswd -c /etc/nginx/.plex-htpasswd alice
The command asks for the password and writes the file nginx reads. Without the-coption, it adds a user to the existing file.Write the virtual host
In
/etc/nginx/conf.d/plex.conf, aserverblock withlisten 443 ssl;,server_name plex.your-domain.com;,auth_basic "Plex";andauth_basic_user_file /etc/nginx/.plex-htpasswd;. Inlocation /, addproxy_pass http://127.0.0.1:32400;,proxy_set_header Host $host;,proxy_http_version 1.1;,proxy_set_header Upgrade $http_upgrade;andproxy_set_header Connection "upgrade";for WebSockets.Get the certificate and reload
sudo certbot --nginx -d plex.your-domain.comsudo nginx -t && sudo systemctl reload nginx
The subdomain's DNS must already point to the VPS before the certificate.Test the three cases
curl -sI https://plex.your-domain.com/must answer 401.curl -s -o /dev/null -w '%{http_code}' https://plex.your-domain.com/player/timelinemust also answer 401 without credentials.curl -sI -u alice https://plex.your-domain.com/asks for the password, then answers 200 or a redirect.
Looking for a compromise that predates the fix
BleepingComputer gives no specific indicator, no hash, address or domain, so we cannot hand you a list of signatures to search for. What remains is behaviour, and it speaks. A media server does not launch a shell, does not download anything in the background, does not burn a whole core continuously and does not contact unknown addresses. Examine the period running from the vulnerable version, and at the very least from the publication of the details in October 2026. No trace does not prove there was no intrusion, since a miner can be renamed; a trace, on the other hand, is a confession.
Seven checks, each with its command
- Unexpected child processes —
ps -eo pid,ppid,user,lstart,args --forest | grep -B1 -A4 -i "plex media server". Normal children carry Plex names (transcoder, script host); ansh, abash, acurlor a binary launched from/tmpis suspect. - CPU usage —
ps aux --sort=-%cpu | head -5. A non-Plex process that keeps the processor busy suggests a cryptominer;pgrep -a -i xmriglooks for the most widespread one, without ruling out a borrowed name. - Unknown files in the Codecs folder —
sudo ls -lat "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Codecs". Plex stores its transcoding codecs there: a name you do not recognise, or a date unrelated to any transcode, deserves a look. Under Docker, the same path sits in the volume mounted on/config. - Recent executables outside packages —
sudo find /tmp /var/tmp /dev/shm /var/lib/plexmediaserver -xdev -type f -perm /111 -mtime -60 2>/dev/null. Any executable in these folders that you did not install needs an explanation. - Outbound connections —
sudo ss -tupn state established | grep -i plexthensudo ss -tupn state established. Look for connections to addresses you do not recognise, especially from a process that is not Plex. - Service logs —
sudo journalctl -u plexmediaserver --since "2026-10-01" | grep -iE "timeline|transcode|error". Look for repeated calls to/player/timelineor transcode errors with no playback in progress. - Persistence —
sudo crontab -l -u plex,sudo systemctl list-timers --allandsudo find /etc/systemd/system /etc/cron.d -mtime -60. A scheduled task or a recent service you did not create is a sign someone wants to come back.
If a trace appears: rebuild rather than clean
A cryptominer found proves an intrusion, but not that it was limited to the miner. First isolate the server: sudo ufw default deny incoming, with SSH allowed from your address only. Export the logs before they rotate, for example with sudo journalctl -u plexmediaserver > plex-journal.txt. Then rebuild the VPS from a clean image, install the fixed version before opening anything, and restore only your media and the library database after review. Finally, change everything the service account could read: SSH keys, Plex password, tokens and environment secrets. A server hardened on the Plex side is still exposed if the kernel does not keep up: see our article on the Fragnesia kernel flaw.
Troubleshooting: five situations we have met
- "plexmediaserver is already the newest version" while the version is old — the Plex repository is not configured on the machine. Download the package from Plex's official download page, then
sudo apt install ./plexmediaserver_*.deb. - The container still shows the old version after
docker pull—docker pulldownloads the image but does not replace the running container. Rundocker compose up -d --force-recreate. - Port 32400 is still reachable despite
ufw deny— Docker writes its own rules and goes ahead ofufw. Publish the port on127.0.0.1:32400:32400as described above. - Plex apps no longer find the server after the port is closed — they were looking for the public address. Go through a VPN and add the server by its tunnel address.
- nginx answers 401 to the apps but not to the browser — the apps do not handle HTTP Basic authentication. Keep the proxy for the browser and give the apps the VPN.
Sources, and what no vendor advisory says
We did not find a Plex security advisory that lists these CVEs. The only vendor item we found is the announcement of version 1.43.3.10861 on the Plex forum, published on 4 August 2026: it mentions neither a flaw nor a CVE. The fixed version number, the mapping of the four CVEs and the score come from BleepingComputer, which cites CISA and the researcher: cross-check with the vendor as soon as it publishes. We give no date for the addition to the KEV catalog, as we could not confirm it on the CISA catalog. And if you would rather leave Plex than harden it, our Jellyfin migration guide covers that separately.
Official documentation
BleepingComputer article on Plex2Shell: https://www.bleepingcomputer.com/news/security/cisa-hackers-chain-plex-flaws-in-plex2shell-attacks-to-breach-servers
Announcement of version 1.43.3.10861 on the Plex forum: https://forums.plex.tv/t/plex-media-server/30447/713
CISA Known Exploited Vulnerabilities catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
Plex Media Server download: https://www.plex.tv/media-server-downloads/
nginx auth_basic module: https://nginx.org/en/docs/http/ngx_http_auth_basic_module.html
Docker and firewalls: https://docs.docker.com/engine/network/packet-filtering-firewalls/
WireGuard quick start: https://www.wireguard.com/quickstart/