Critical CVE Response

Is Your Plex Server Actually Patched? Plex2Shell Chains Four Medium CVEs to Unauthenticated RCE

Dark cyberpunk illustration of a tall stack of black glass slabs in a cold server room, one slab near the top blown open with orange light, cyan data filaments spilling down to the floor grid while a thin cyan beam passes straight through the breach.

Open Plex Web, go to Settings and then General, and read the version number. If it says 1.43.3, that check has told you nothing. Plex closed the Plex2Shell chain in build 1.43.3.10861. Build 1.43.3.10828 prints the same three-part version and still hands an unauthenticated attacker code execution on the host. Censys counted roughly 8,000 servers sitting on that one build in its October 20 advisory, published the same day CISA added four Plex Media Server CVEs to the Known Exploited Vulnerabilities catalog.

Plex confirmed the attacks a day earlier. Its September security notice picked up an October 19 update that says "These vulnerabilities are being actively and widely exploited." A public proof of concept landed on October 16, the first honeypot hits followed on October 17, and the payloads reported so far are a Monero miner and proxy software that rents the host's bandwidth to someone else.

Who has to act, and who does not

This is yours if any machine you are responsible for runs Plex Media Server. That includes a workstation, a home-office desktop that sits on the VPN, a Synology or QNAP box in a closet, and a container somebody stood up on the file server one afternoon. If nothing in your estate runs Plex, this one is not yours, and for most business networks that is the correct answer. Confirm it and go do something else.

Confirming it from memory is where this goes wrong. Nobody in IT deployed Plex. Somebody on the network may have. It does not show up in an inventory that only covers managed images, it does not arrive through the patching tool, and its remote-access feature asks the gateway for a port forward on its own, with no change ticket behind it.

The account it runs as is what makes this a business problem rather than a hobbyist one. Plex tells compromised operators to treat anything the Plex service account could reach as exposed, and it names mounted shares and stored credentials specifically. On a NAS, that account routinely reads the same volumes as the accounting share. Code execution inside a media server is code execution on a file server that happens to have a media app installed.

Four medium CVEs, one unauthenticated shell

Not one CVE in this chain is rated critical. NVD scores them under CVSS 4.0 at 5.3, 6.9, 5.3 and 8.6. Under CVSS 3.1 the highest of the four is 7.2. A vulnerability queue that sorts by severity and cuts at 9.0 drops all four. A queue that cuts at 8.0 keeps one. The researcher who published the chain rates the end-to-end result 9.8. Both numbers are defensible, they measure different objects, and only one of them describes what the attacker walks away with.

The sequence, taken from the NVD records:

  • CVE-2026-96652, CVSS 4.0 of 5.3. Server-side request forgery on /player/timeline. NVD's wording carries the whole problem: an attacker "using any X-Plex-Token value can include a full URL in the 'protocol' parameter and force the Plex server to POST to the attacker's chosen destination." Any value. The server checks that the header is present.
  • CVE-2026-96654, 6.9. URL values inside searchOne are not neutralized, so the request can call other plugins' functions with attacker-chosen parameters. Aimed at loopback, that reaches an internal agent the server trusts, and Plex attaches the owner's admin token on the way.
  • CVE-2026-96655, 5.3. A second request-forgery primitive, on the /video/:/transcode/universal path parameter, usable once the first two have produced an authenticated context.
  • CVE-2026-96656, 8.6. The payoff. The TranscoderH264Options preference "is appended verbatim to x264's option string on every transcode," which converts an admin setting into an arbitrary file write. NVD then states the other half: "At startup, all .so files are run without signature, execute bit, or symbol checks." Write a shared object into the Codecs directory, wait for a restart, get execution.

Lay the dependencies next to the scores and they stop disagreeing. Each flaw consumes the privilege the previous one manufactured. The file write is rated PR:H because it really does require an administrator, and the first three exist to produce one.

The version string is a false negative

Plex shipped the fixed build on August 4 and published the notice on September 1. NVD published the CVEs on September 23. The exploit went public on October 16. Six weeks of warning left a population Censys measured at about 324,000 Plex hosts, with roughly 30 percent still on a vulnerable build when the advisory went out.

The 8,000 hosts on 1.43.3.10828 are the interesting group, because those operators did update. They read the notice, moved to 1.43.3, saw the version they were told to reach, and stopped. Compare the fourth segment as an integer instead: 10828 is lower than 10861.

# Linux, macOS, NAS: Plex answers /identity without authentication.
BUILD=$(curl -s --max-time 3 http://127.0.0.1:32400/identity \
  | sed -n 's/.*version="[0-9]*\.[0-9]*\.[0-9]*\.\([0-9]*\).*/\1/p')
echo "build $BUILD"
[ "${BUILD:-0}" -ge 10861 ] && echo "PATCHED" || echo "VULNERABLE"
# Windows: read the build off the service binary, not Programs and Features.
$exe = Join-Path ${env:ProgramFiles(x86)} 'Plex\Plex Media Server\Plex Media Server.exe'
$v   = (Get-Item $exe -ErrorAction Stop).VersionInfo.FileVersion   # 1.43.3.10828
if ([int]($v.Split('.')[3]) -ge 10861) { "PATCHED $v" } else { "VULNERABLE $v" }

Programs and Features on Windows reports the version that was originally installed and will give you a comforting wrong answer after an in-app update.

Find the servers nobody told you about

Plex binds TCP 32400 and answers /identity to anyone who asks. That is convenient for an attacker and equally convenient for you. One sweep per user VLAN produces an inventory that no agent-based tool will give you, because the hosts running this are the hosts your agent is not on.

# Sweep a VLAN for Plex and print each server's build in one pass.
nmap -Pn -p 32400 --open -oG - 10.20.0.0/24 \
  | awk '/32400\/open/ {print $2}' \
  | while read -r ip; do
      v=$(curl -s --max-time 3 "http://$ip:32400/identity" \
          | sed -n 's/.*version="\([^"]*\)".*/\1/p')
      printf '%s\t%s\n' "$ip" "${v:-no-answer}"
    done

Then check the edge. Plex's Remote Access feature asks the gateway to forward TCP 32400 over UPnP or NAT-PMP, and most consumer and small-business routers will grant it without logging anything a human reads. Export the current port-forward table and look for 32400, or for any external port mapped to an internal host on 32400. If the gateway logs UPnP lease requests at all, that log is a standing list of the software on your network that asked to be reachable from the internet. Plex's own advice on this is blunt: turn Remote Access off if you do not need it, and avoid forwarding 32400 directly.

If it answered from the internet, work it as a compromise

Plex's position is that a server older than 1.43.3.10861 and reachable from the internet should be assumed compromised. The indicator list it published is short enough to check in a few minutes per host.

# 1. Unsigned shared objects or DLLs dropped into the Codecs directory.
find "$PLEX_DATA/Codecs" \( -name '*.so' -o -name '*.dll' \) \
     -newermt '2026-08-04' -printf '%T+  %10s  %p\n' | sort

# 2. Transcoder options nobody set. This is the CVE-2026-96656 write primitive.
grep -oE 'Transcoder[A-Za-z0-9]*="[^"]*"' "$PLEX_DATA/Preferences.xml"

# 3. The outbound destination Plex names in its notice.
grep -r 'proxystream\.st' /var/log/ 2>/dev/null

If you run Defender for Endpoint on the host, the same three questions fit in one query, and the process-parent angle catches payloads whose domain has already rotated.

DeviceNetworkEvents
| where Timestamp > ago(21d)
| where InitiatingProcessFileName has "Plex"
| summarize Connections = count(), FirstSeen = min(Timestamp)
        by DeviceName, RemoteUrl, RemoteIP, InitiatingProcessFileName
| where RemoteUrl !endswith "plex.tv" and RemoteUrl !endswith "plex.direct"
| order by Connections desc

Sustained high CPU while nothing is playing is the fourth signal, and it is the one a user will report for you if you ask them. A miner on a transcoding box hides inside a workload that is supposed to spike.

What that service account could reach

Upgrading closes the chain. It evicts nothing already sitting in the Codecs directory, and it does not revoke a token the attacker has already read. Plex's remediation is a rebuild from a clean installation rather than a reuse of the old data directory. The floor, if a rebuild is not happening today, is emptying the Codecs folder, auditing Preferences.xml for transcoder options you did not set, signing out of all devices from the Plex account and changing that password.

The part the vendor can only gesture at is yours. Enumerate what the service account could read: mapped drives, NAS volumes mounted for the media library, credentials sitting in a config file beside the data directory, SSH keys in the account's home directory, a backup target mounted for convenience. On a small network that list is usually longer than anyone expects, because the media server was installed on the box that already had the storage. If that account could read the finance share, so could whoever ran the miner. Crypto mining is what the first operator through the door chose to monetize, and the access is reusable.

Treat the token the same way. The chain works by making Plex hand over the owner's admin token, so that credential should be considered disclosed on any server that was reachable while unpatched, regardless of what you find on disk.

Read the build number off every host before you close the ticket

Three steps, in this order. Sweep your user networks for TCP 32400 and write down every answer, because you cannot patch what nobody told you about. For each server found, compare the fourth segment of the build against 10861 and upgrade anything below it. For any server that was reachable from the internet while it was below that number, run the Codecs and Preferences checks and plan the rebuild rather than trusting the upgrade.

The sweep costs an afternoon. The third step is the one that decides whether this was a patch or an incident, and it is the step most teams will skip because the affected machine is "just a media server." If you want another set of eyes on the discovery sweep, or on what a compromised host in that position could actually reach, that is the kind of question we work through with small teams regularly.

Not sure what is listening on your network?

We run external and internal discovery for organizations that need to know what is actually reachable before an advisory forces the question, and we help scope the cleanup when a host turns out to have been exposed. Book a session to walk through your environment.