Like rating a detonator as 'moderate' because someone else lit the fuse
CVE-2026-96656 allows an admin-authenticated Plex Media Server user to inject a path into the TranscoderH264Options preference, causing the x264 encoder to write attacker-controlled data to the Codecs directory via the dump-yuv flag. On next transcode or service restart, avpriv_load_new_libs calls dlopen(RTLD_NOW) on every .so file in that directory — no signature check, no execute-bit check, no symbol validation. ELF constructors fire immediately, granting code execution as the Plex service user (typically uid=1000, or root in many Docker deployments). All Plex Media Server versions before 1.43.3.10861 are affected.
The vendor scored this CVE at 7.2 HIGH with PR:H — technically correct *if you pretend it exists in a vacuum*. It does not. CVE-2026-96656 is the terminal link in the Plex2Shell chain (CVE-2026-96652 → 96654 → 96655 → 96656), which achieves unauthenticated remote code execution from the internet with zero user interaction. The three preceding CVEs — an unauth SSRF, a loopback auth bypass with injection, and a token-theft SSRF — completely eliminate the PR:H requirement. A weaponized PoC was published October 16, 2026; exploitation in the wild was confirmed within 24 hours. Shadowserver counted 36,000+ exposed, unpatched instances as of early September — before the PoC even dropped. The 7.2 is dangerously misleading. The real-world severity of this CVE in context is CRITICAL.
5 steps from start to impact.
Unauthenticated SSRF via /player/timeline
/player/timeline endpoint with X-Plex-Token: junk and an injected protocol= parameter containing a full http://127.0.0.1:32400/system/agents/... URL. Plex validates only that a token header *exists*, not that it's valid. When the fake player subscription is cancelled, Plex POSTs the callback from genuine loopback origin. No authentication required. This is CVE-2026-96652.- Network access to Plex port 32400 (TCP)
- Plex Media Server < 1.43.3.10861
- Plex is *designed* to be internet-facing; Remote Access is enabled by default; ~295K instances visible on Shodan port 32400
/player/timeline with injected protocol= containing 127.0.0.1 would catch this.Loopback auth bypass + identifier injection
/system/agents/*/searchOne, which grants unauthenticated access to requests from 127.0.0.1. A broken decorator fails to halt execution when the agent identifier is unregistered. The attacker injects a ? into the identifier= parameter to append arbitrary query-string arguments, forging a call to GetResultFromNetwork on the TheTVDB plugin agent. This is CVE-2026-96654.- Successful SSRF from step 1 (loopback POST)
- Fully automated by the chain — no additional attacker interaction needed
/system/agents/ requests with ? in identifier parameters. No commercial scanner signature known at time of assessment.Admin token exfiltration via sslip.io DNS rebinding
GetResultFromNetwork fetches arbitrary URLs. Outbound requests starting with http://127.0.0.1 automatically receive the owner's admin token in the request. The attacker uses a sslip.io subdomain (e.g., 127.0.0.1.attacker.sslip.io) so the prefix check passes but DNS resolves to the attacker's server, leaking the owner token. This is the bridge between CVE-2026-96654 and CVE-2026-96655.- Outbound HTTP from Plex to attacker-controlled host (common — Plex fetches metadata constantly)
- DNS resolution of sslip.io subdomains (not blocked by most deployments)
- Requires outbound HTTP, which nearly all Plex instances permit
- sslip.io is a legitimate service; blocking it would break other tooling
*.sslip.io queries from Plex hosts. Outbound request logging showing owner token in Authorization headers to non-Plex destinations.Arbitrary file write via transcoder dump-yuv
TranscoderH264Options preference to dump-yuv=/config/Library/Application Support/Plex Media Server/Codecs/<platform>/payload.so:qp=0, then triggers a transcode via /video/:/transcode/universal. The x264 encoder writes bit-exact decoded frames to the attacker-chosen path — an ELF shared object crafted as the 'video' input. This is CVE-2026-96655 combined with the CVE-2026-96656 write primitive.- Valid owner admin token (obtained in step 3)
- Plex transcoder enabled (default)
- Transcoding is a core Plex feature and virtually never disabled
- The Codecs directory is writable by the Plex process by design
Codecs/ directory. Detection of TranscoderH264Options being modified via the API.Code execution via unsigned dlopen
avpriv_load_new_libs enumerates all .so files in the Codecs platform subdirectory and loads them via dlopen(RTLD_NOW). No signature verification, no execute-bit check, no expected-symbol validation. The attacker's ELF constructor runs immediately with the privileges of the Plex process — typically uid=1000 on bare metal or root in Docker. Observed payloads include XMRig cryptominer and a residential proxy backdoor. This is CVE-2026-96656.- Malicious .so written to Codecs directory (step 4)
- Transcoder re-initialization or service restart
- The attacker can trigger a transcode request themselves using the stolen admin token, making this near-instantaneous
dlopen of unknown shared objects. Process tree analysis showing unexpected child processes (wget, curl, sh) spawned by the Plex Transcoder process.<Plex data>/Codecs/<platform>/ for any .so files not matching known Plex codec hashes. The observed malicious payload was named zz45fbb275.so containing a wget/curl dropper. If found, assume full host compromise and rebuild. This is a detection/response action, not a preventive control, but it identifies already-compromised hosts.wget, curl, sh, bash, or unknown binaries. Configure EDR or process-monitoring rules to alert on this. This detects exploitation but does not prevent it.217.60.194.116 (payload host), 45.194.92.222, 91.92.40.202, 176.65.139.228 (scanning IPs) at the network perimeter. Also block DNS resolution of *.sslip.io from Plex hosts to break the token-exfiltration step. Note: blocking sslip.io alone breaks step 3 but does not patch the underlying vulnerabilities.- Plex authentication / strong admin password — irrelevant because the chain steals the owner token via SSRF + DNS rebinding; it never brute-forces credentials.
- WAF rules on /player/timeline — the SSRF payload is in the
protocol=query parameter, not the request body; most WAFs won't inspect URL parameters for SSRF patterns against loopback addresses by default, and Plex doesn't typically sit behind a WAF. - Disabling transcoding only — while this prevents the
dump-yuvfile-write step, the attacker still obtains the admin token and can explore other post-auth attack surfaces; it's a partial mitigation at best and breaks core Plex functionality. - Running Plex in Docker without
--privileged— while this limits blast radius, the exploit still achieves code execution *inside* the container as whatever user Plex runs as (often root in official Plex Docker images), enabling cryptomining, proxy deployment, and container-level persistence.
The supporting signals.
| In-the-Wild Exploitation | Confirmed active. Exploitation observed on honeypots within 24 hours of PoC release (October 17, 2026). Three scanning IPs identified: 45.194.92.222, 91.92.40.202, 176.65.139.228. Payload served from 217.60.194.116. Payloads: XMRig Monero miner + myawesomeproxy residential proxy backdoor. |
|---|---|
| Proof-of-Concept | Public, weaponized. Full chain PoC: code-zm/plex2shell (published October 16, 2026 by Zach Main / @zm_0x). Standalone CVE-2026-96656 PoC by a3igner on Sploitus (October 18, 2026). Writeup at zmain.info/blog/plex2shell. |
| EPSS | 0.00396 (0.4%) — 68th percentile. EPSS has not yet caught up to the active exploitation reality; expect a significant jump in the next scoring cycle. |
| CISA KEV | Not listed as of 2026-10-19. Given confirmed in-the-wild exploitation, KEV addition is likely imminent. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H (7.2) — the PR:H is the critical disconnect; the Plex2Shell chain eliminates the admin-auth prerequisite entirely. CVSS v4.0 score: 8.6. Researcher-assessed chain aggregate: CVSS 10.0. |
| Affected Versions | Plex Media Server < 1.43.3.10861 (all platforms: Linux, Windows, macOS, NAS/Docker). Confirmed vulnerable: 1.43.2.10687 and earlier. Fix build: 1.43.3.10861 (released August 4, 2026). |
| Exposure Data | Shodan: ~295,694 Plex instances on port 32400. Shadowserver: 36,000+ unpatched instances reported September 4–9, 2026 — *before* the PoC was published. Attack surface is large and predominantly residential/prosumer, but includes enterprise media and NAS deployments. |
| Disclosure Timeline | July 27, 2026: reported to [email protected]. August 4: fix shipped (1.43.3.10861). September 1: Plex advisory (no CVEs, no details). September 23: CVEs assigned. October 16: public PoC. October 17: in-the-wild exploitation. |
| Researcher | Zach Main (@zm_0x, github.com/code-zm). Plex paid a bounty (reported as $500 for a full unauth RCE chain). Additional standalone PoC by a3igner. |
| Related CVEs | CVE-2026-96652 (unauth SSRF, 4.3), CVE-2026-96654 (loopback bypass + injection, 6.5), CVE-2026-96655 (transcoder SSRF + file write, 4.3). All four are co-dependent in the Plex2Shell chain. Also related: CVE-2026-96651 (path traversal, 6.5). |
Sources.
- Plex2Shell Full Writeup — Zach Main
- Plex2Shell PoC Repository — code-zm/plex2shell
- SecurityOnline — Plex2Shell Exploited in the Wild
- BleepingComputer — Over 36,000 Plex Servers Unpatched
- CordCuttersNews — Plex Exploitation Advisory
- Blacktree.nl — Plex Security Update Analysis
- OpenCVE — CVE-2026-96656 Details
- Threat Radar — CVE-2026-96656 Intelligence
Why this verdict
- PR:H is fictional in practice. The vendor's CVSS 7.2 hinges on
PR:H(admin privileges required). The Plex2Shell chain (CVE-2026-96652 → 96654 → 96655 → 96656) eliminates this requirement entirely — the attacker steals the owner token via an unauthenticated SSRF and DNS rebinding trick. No real-world attacker exploits CVE-2026-96656 in isolation. AdjustingPR:HtoPR:Nalone moves the CVSS base to 9.8. - Active exploitation with weaponized PoC. A full-chain PoC was published October 16, 2026. Exploitation was observed in the wild within 24 hours. This is not theoretical — real payloads (XMRig miner, residential proxy) are being dropped on real servers. This eliminates any residual benefit-of-the-doubt that might keep the score below CRITICAL.
- Large, reachable attack surface. Plex Media Server is *designed* to be internet-facing (Remote Access is on by default). Shodan shows ~295K instances on port 32400. Shadowserver identified 36,000+ unpatched instances in early September — weeks before the PoC dropped. The friction to reach the first step of the chain is effectively zero for a significant population.
- Zero interaction required. The full chain from initial SSRF to code execution requires no user interaction, no clicking links, no social engineering. The attacker automates the entire sequence against any reachable Plex instance.
UI:Nthroughout. - Role multiplier: Plex Media Server is not a canonical high-value enterprise component (it's a media server, not an IdP/DC/hypervisor/CA). However: (a) *Home/prosumer NAS role* (~85% of installs) — chain succeeds, blast radius is host-level RCE as uid=1000 or root-in-Docker, plus residential IP proxy weaponization; this is the observed real-world outcome. (b) *Enterprise media/file server role* (~10%) — chain succeeds, blast radius is host compromise + potential lateral movement into corporate networks; Plex on a NAS often has access to shared storage. (c) *Docker-root role* (~15-30% of installs run Plex in Docker, often as root) — chain succeeds, blast radius escalates to container escape potential or host-level root if
--privilegedor host-network mode. The internet-facing nature and the residential-proxy weaponization model mean compromised Plex instances become *infrastructure* for further attacks on corporate VPNs and email systems. While the per-host blast radius is 'only' host-level (not domain/fleet/supply-chain), the *population scale* (36K+ exposed, unpatched) and confirmed exploitation push this to CRITICAL.
Why not higher?
A 10.0 would require Scope change (S:C) or a blast radius beyond the compromised host. CVE-2026-96656 executes as the Plex service user, not SYSTEM/root (except in misconfigured Docker deployments). There is no inherent privilege escalation beyond the Plex process context, and lateral movement requires additional post-exploitation steps. The 9.8 reflects the full unauth-RCE chain reality with active exploitation but correctly caps below 10.0 due to unchanged scope.
Why not lower?
The admin-auth prerequisite that anchors the vendor's 7.2 is completely bypassed by the publicly weaponized Plex2Shell chain. Any assessment below CRITICAL ignores: (1) confirmed in-the-wild exploitation within 24 hours of PoC release, (2) 36,000+ internet-exposed unpatched targets, (3) zero-interaction full chain, and (4) the fact that no real-world attacker uses CVE-2026-96656 without the preceding chain CVEs. Treating this as a standalone HIGH-severity admin-only bug would be malpractice.
Crowdsourced verification payload.
Run this script on each host running Plex Media Server (Linux/macOS/NAS). It checks the installed version and inspects the Codecs directory for suspicious .so files. Requires read access to the Plex binary and data directory. Invoke: sudo bash check_plex_cve2026_96656.sh (sudo needed to read Plex data dirs owned by the plex user).
#!/usr/bin/env bash
# check_plex_cve2026_96656.sh — Detect CVE-2026-96656 (Plex2Shell chain)
# Run on target Plex Media Server host as root or plex user.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -euo pipefail
FIXED_VERSION="1.43.3.10861"
RESULT="UNKNOWN"
# Locate Plex Media Server binary
PLEX_BIN=""
for candidate in \
/usr/lib/plexmediaserver/Plex\ Media\ Server \
/usr/lib/plexmediaserver/"Plex Media Server" \
/Applications/Plex\ Media\ Server.app/Contents/MacOS/Plex\ Media\ Server \
/volume1/@appstore/PlexMediaServer/Plex\ Media\ Server; do
if [[ -x "$candidate" ]] 2>/dev/null; then
PLEX_BIN="$candidate"
break
fi
done
# Try Docker if no local binary
if [[ -z "$PLEX_BIN" ]]; then
DOCKER_VER=$(docker exec plex /usr/lib/plexmediaserver/"Plex Media Server" --version 2>/dev/null || true)
if [[ -n "$DOCKER_VER" ]]; then
INSTALLED_VERSION=$(echo "$DOCKER_VER" | grep -oP '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
fi
# Get version from binary
if [[ -n "${PLEX_BIN:-}" ]]; then
RAW_VER=$("$PLEX_BIN" --version 2>/dev/null || true)
INSTALLED_VERSION=$(echo "$RAW_VER" | grep -oP '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
if [[ -z "${INSTALLED_VERSION:-}" ]]; then
echo "[UNKNOWN] Could not determine Plex Media Server version."
echo "Ensure Plex is installed and the script is run with appropriate permissions."
exit 2
fi
echo "Installed Plex version: $INSTALLED_VERSION"
echo "Fixed version: $FIXED_VERSION"
# Compare versions (dot-separated numeric)
version_gte() {
local IFS=.
local i a=($1) b=($2)
for ((i=0; i<${#b[@]}; i++)); do
if (( ${a[i]:-0} > ${b[i]:-0} )); then return 0; fi
if (( ${a[i]:-0} < ${b[i]:-0} )); then return 1; fi
done
return 0
}
if version_gte "$INSTALLED_VERSION" "$FIXED_VERSION"; then
RESULT="PATCHED"
else
RESULT="VULNERABLE"
fi
# Check Codecs directory for suspicious .so files (indicator of compromise)
CODEC_DIRS=(
"/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Codecs"
"$HOME/Library/Application Support/Plex Media Server/Codecs"
"/config/Library/Application Support/Plex Media Server/Codecs"
)
SUSPICIOUS_FILES=0
for cdir in "${CODEC_DIRS[@]}"; do
if [[ -d "$cdir" ]]; then
while IFS= read -r -d '' sofile; do
# Check for suspicious strings in .so files
if strings "$sofile" 2>/dev/null | grep -qiE '(wget|curl|/bin/sh|xmrig|mining|proxy|sslip\.io)'; then
echo "[IOC] Suspicious .so file: $sofile"
SUSPICIOUS_FILES=$((SUSPICIOUS_FILES + 1))
fi
done < <(find "$cdir" -name '*.so' -print0 2>/dev/null)
fi
done
if [[ $SUSPICIOUS_FILES -gt 0 ]]; then
echo "[ALERT] Found $SUSPICIOUS_FILES suspicious .so file(s) in Codecs directory — possible active compromise!"
fi
echo ""
echo "[$RESULT] CVE-2026-96656 (Plex2Shell chain)"
if [[ "$RESULT" == "VULNERABLE" ]]; then
exit 1
elif [[ "$RESULT" == "PATCHED" ]]; then
exit 0
else
exit 2
fi