On 2026-10-20, CISA added four Plex Media Server vulnerabilities to its Known Exploited Vulnerabilities (KEV) catalog: CVE-2026-96656, CVE-2026-96654, CVE-2026-96655 and CVE-2026-96652. A fifth bug from the same advisory, CVE-2026-96651, is not in KEV, but it is the piece that turns an “admin only” code execution bug into something a regular session holder can reach. All five are fixed in Plex Media Server 1.43.3.10861. If your home media server is older than that, it needs attention today.

This guide is for self-hosters running Plex on Debian or Ubuntu (with a short section for Docker). It covers three questions in order: am I vulnerable, was I compromised, and how do I patch. It also covers the apt signing key gotcha that leaves many servers silently stuck on old builds after an Ubuntu release upgrade.

What Was Fixed and Why the Chain Matters

All five CVEs were published in NVD on 2026-09-23, alongside the CISA CSAF advisory va-26-266-01 titled “Plex Media Server” and Plex’s release notes. Every NVD record says the same thing about affected versions: “before 1.43.3.10861”. Plex also posted Important security update for Plex Media Server v1.43.2 and earlier, which the KEV entries link to. The researcher write-up, titled plex2shell, describes the chain to code execution.

CVEIssueCVSS 4.0CVSS 3.1Auth requiredCISA KEV
CVE-2026-96656Admin can write files that are executed on load (x264 options and startup .so loading)8.6 HIGH7.2 HIGHAdminAdded 2026-10-20, due 2026-10-23
CVE-2026-96651Path traversal in /system/agents/media/get reads any file the PMS user can read, including PlexOnlineToken7.1 HIGH6.5 MEDIUMSession tokenNot listed
CVE-2026-96652SSRF via /player/timeline (protocol parameter)5.3 MEDIUM4.3 MEDIUMLowAdded 2026-10-20, due 2026-11-03
CVE-2026-96654searchOne does not neutralize URL values, so callers can invoke other plugins’ functions with their own parameters6.9 MEDIUM6.5 MEDIUMNoneAdded 2026-10-20, due 2026-10-23
CVE-2026-96655SSRF via the /video/:/transcode/universal path parameter5.3 MEDIUM4.3 MEDIUMLowAdded 2026-10-20, due 2026-11-03

Scores are the CNA scores shown in NVD. Note that there is no Plex CVE-2026-96653; that ID belongs to an unrelated WordPress plugin, so do not treat this as a contiguous range. CISA lists known ransomware use as “Unknown” for all four KEV entries.

How the pieces fit together

CVE-2026-96656 is the code execution primitive. According to NVD, the TranscoderH264Options preference is appended verbatim to the x264 option string on every transcode. Separately, at startup Plex loads every .so file it finds without checking signatures, execute bits or symbols. An attacker who can set preferences can therefore get a file written to disk during a transcode and have it loaded as native code the next time the server starts. On its own this requires admin rights, which is why the CVSS 4.0 vector says PR:H.

The other bugs remove that requirement:

  • CVE-2026-96651 lets anyone with a valid session token (a shared user, a friend you gave library access to, or a stolen client token) read arbitrary files. Preferences.xml holds the server’s PlexOnlineToken, and NVD notes that this token gives control of both the account and the server. NVD also notes that a LAN-adjacent attacker supplying their own X-Forwarded-For header can do the same.
  • CVE-2026-96654 needs no authentication at all and lets a caller drive other plugins’ functions.
  • CVE-2026-96652 and CVE-2026-96655 are server-side request forgery bugs that let the server be used to reach internal or external addresses.

So the realistic path is: get a session (or abuse the unauthenticated surface), read the owner token, act as admin, and then use the preference and library loading behavior to run code as the plex user. That combination is what CISA is responding to.

Exposure is not hypothetical. SC World, citing Shadowserver, reported more than 36,000 Plex Media Servers still unpatched against these issues. That figure is theirs, not ours, but it matches what you would expect from a product that self-hosters install once and forget.

Am I Vulnerable?

You are vulnerable if your Plex Media Server version is lower than 1.43.3.10861. The current release on the Plex repo and downloads API is 1.43.5.11079-b3b13e506.

Check the installed version

On Debian or Ubuntu, ask dpkg:

bash
dpkg -l plexmediaserver | awk '/^ii/ {print $2, $3}'
text
plexmediaserver 1.42.2.10156-<build-hash>

The /identity endpoint reports the running version without a token, which is handy because it reflects what is actually executing rather than what is on disk:

bash
curl -s http://127.0.0.1:32400/identity | grep -o 'version="[^"]*"'
text
version="1.42.2.10156-<build-hash>"

In the Web UI, the version is shown under Settings > General for the server.

To get a clear pass or fail, let dpkg compare versions for you:

bash
#!/usr/bin/env bash
set -euo pipefail
fixed="1.43.3.10861"
running=$(curl -s http://127.0.0.1:32400/identity | sed -n 's/.*version="\([^"]*\)".*/\1/p')
if [ -z "$running" ]; then
  echo "Could not read version from /identity" >&2
  exit 2
fi
if dpkg --compare-versions "$running" lt "$fixed"; then
  echo "VULNERABLE: running $running (fixed in $fixed)"
  exit 1
fi
echo "OK: running $running"

Check exposure

Version tells you whether the bugs exist. Exposure tells you who can reach them.

  1. Remote Access. In the Web UI, open Settings > Remote Access. If it shows “Fully accessible outside your network”, the server is reachable from the internet on a public port.
  2. Router port forwards. Look for a manual forward to TCP 32400 (or whatever public port you configured).
  3. UPnP and NAT-PMP. If UPnP is enabled on the router, Plex may have opened a port by itself. From any Linux host on the LAN, miniupnpc can list current mappings:
bash
sudo apt install -y miniupnpc
upnpc -l | grep -i -E 'plex|32400'
  1. Who has session tokens. Every shared user and every signed-in device holds a token. CVE-2026-96651 means each of those is a potential path to your owner token, so even a server that is “only shared with family” is in scope.

Was I Compromised?

The checks below are read-only. Run them before you upgrade, because upgrading and restarting changes file times and rotates logs. The default data directory on Debian and Ubuntu is used throughout:

bash
PMS_DATA="/var/lib/plexmediaserver/Library/Application Support/Plex Media Server"

1. Inspect Preferences.xml keys without printing values

List the attribute names and nothing else:

bash
sudo grep -o ' [A-Za-z0-9]*=' "$PMS_DATA/Preferences.xml" | tr -d ' =' | sort -u

Or with Python, which parses the XML properly:

bash
sudo python3 -I -c 'import sys, xml.etree.ElementTree as E; print("\n".join(sorted(E.parse(sys.argv[1]).getroot().attrib)))' "$PMS_DATA/Preferences.xml"

Then filter for transcoder settings:

bash
sudo python3 -I -c 'import sys, xml.etree.ElementTree as E; print("\n".join(k for k in sorted(E.parse(sys.argv[1]).getroot().attrib) if k.startswith("Transcoder")))' "$PMS_DATA/Preferences.xml"

The key you care about most is TranscoderH264Options. Most installs never set it. If it is present and you did not add it yourself, treat that as a strong indicator. Any other Transcoder* key you do not recognize deserves a closer look in the Web UI (Settings > Transcoder) rather than by dumping the file.

2. Verify package files

dpkg -V compares installed files against the package’s checksums. No output means nothing in the package has changed:

bash
sudo dpkg -V plexmediaserver

A line such as ??5?????? /usr/lib/plexmediaserver/... means a binary or library shipped by the package has been modified. Configuration files may legitimately differ, but binaries should not.

3. Look for shared objects the package does not own

The data directory is not owned by the package, so dpkg -V cannot see it. List every shared object under it with its modification time:

bash
sudo find "$PMS_DATA" -type f -name '*.so*' -printf '%TY-%Tm-%Td %TH:%TM  %u  %p\n' | sort

Files under Codecs/<hash>/ are normal. Plex downloads codec libraries there, and their timestamps typically line up with an upgrade or first transcode. Compare against your package history:

bash
grep -E ' (install|upgrade) plexmediaserver' /var/log/dpkg.log* 2>/dev/null

What to flag:

  • .so files outside Codecs/, for example in Cache/, Logs/, Plug-in Support/ or the top of the data directory.
  • .so files inside Codecs/ whose time does not match an upgrade or codec download.
  • Files written after a known-good reference point:
bash
sudo find "$PMS_DATA" -type f -name '*.so*' -newer /usr/lib/plexmediaserver/Plex\ Media\ Server -printf '%TY-%Tm-%Td %TH:%TM  %p\n'

4. Processes, cron and /tmp for the plex user

Code that runs through PMS runs as the plex user. Look at what that account is doing:

bash
ps -u plex -o pid,ppid,lstart,cmd --forest
sudo crontab -l -u plex 2>&1
sudo find /tmp /var/tmp /dev/shm -user plex -printf '%TY-%Tm-%Td %TH:%TM  %p\n' 2>/dev/null
sudo ss -tnp | grep -i plex

Expected children of Plex Media Server include the transcoder, the plug-in host and tuner or scanner helpers. A shell, curl, wget, nc, or a binary running out of /tmp is not expected. A crontab for plex is also unusual on a package install.

5. Logs

PMS logs live in $PMS_DATA/Logs/. Search for preference writes and searchOne calls, and strip query strings so you do not print tokens:

bash
sudo grep -h -E 'PUT /:/prefs|searchOne' "$PMS_DATA"/Logs/Plex\ Media\ Server*.log \
  | sed -E 's/\?[^ ]*//g' | sort | uniq -c | sort -rn | head -50

A preference write you did not make, especially around a time you were not using the UI, is worth chasing. Be realistic about what this proves: PMS rotates its logs quickly, often keeping only a few days, so finding nothing is weak evidence. Finding something is strong evidence.

If anything turns up

Treat the host as compromised. Code execution as plex means the attacker had whatever that user can reach, including your media, the database and the owner token.

  1. Disconnect the server from the network or stop plexmediaserver.
  2. From a clean machine, change your plex.tv password and sign out all devices (see Hardening below).
  3. Rebuild the host from a known-good image. Do not try to clean it in place.
  4. Restore media from storage you trust, and restore the Plex database only if you are confident it was not modified. Do not restore Preferences.xml; let the new install claim the server fresh.

Patch Plex Media Server

On a host with a working Plex repo, patching is one command:

bash
sudo apt update
sudo apt install --only-upgrade plexmediaserver
curl -s http://127.0.0.1:32400/identity | grep -o 'version="[^"]*"'

If the version did not move, you have probably hit the gotcha below.

The Ubuntu release upgrade gotcha

do-release-upgrade disables third-party apt sources as part of the upgrade. Plex’s repo is one of them, so after moving to a new Ubuntu release the server keeps running happily on whatever build it had, and apt upgrade reports nothing to do. That is exactly how a home media server can fall many months behind without anyone noticing.

The natural fix is to re-enable the old source. That then fails with:

text
W: GPG error: https://repo.plex.tv/deb public InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 0A05F1E6E7AFD573
E: The repository 'https://repo.plex.tv/deb public InRelease' is not signed.

The reason is that Plex no longer signs the repo with its 2015 key (PlexSign.key, rsa4096 97203C7B3ADCA79D). The Release file is now signed by 0A05F1E6E7AFD573, an ed25519 signing subkey of PlexSign.v2. The old keyring simply cannot verify it.

Install the PlexSign.v2 key

Fetch the key into its own keyring:

bash
curl -fsSL https://downloads.plex.tv/plex-keys/PlexSign.v2.key \
  | gpg --dearmor \
  | sudo tee /usr/share/keyrings/plexmediaserver.v2.gpg >/dev/null
sudo chmod 0644 /usr/share/keyrings/plexmediaserver.v2.gpg

Verify the fingerprint before you trust it:

bash
gpg --show-keys --with-subkey-fingerprints /usr/share/keyrings/plexmediaserver.v2.gpg

You should see a primary key with fingerprint 6EFF EB47 8A65 59D7 5C7C 4FE7 06C5 2179 0B9C FFDE and the uid Plex Inc. (SHA-512), plus an ed25519 signing subkey ending in 0A05 F1E6 E7AF D573 (full fingerprint B406 F089 7A39 A570 8042 6054 0A05 F1E6 E7AF D573, created 2024-02-20, expiring 2029-02-18). If the primary fingerprint does not match, stop and do not install the repo.

Add the repo as a deb822 source

Remove any stale or disabled Plex entries first (file names vary; check before deleting):

bash
ls /etc/apt/sources.list.d/ | grep -i plex
grep -rn 'repo.plex.tv\|downloads.plex.tv' /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null

Then create a single deb822 source that pins the new keyring:

bash
sudo tee /etc/apt/sources.list.d/plexmediaserver.sources >/dev/null <<'EOF'
Types: deb
URIs: https://repo.plex.tv/deb
Suites: public
Components: main
Signed-By: /usr/share/keyrings/plexmediaserver.v2.gpg
EOF

Signed-By scopes the key to this one repo, which is better practice than dropping it into /etc/apt/trusted.gpg.d/, where it would be trusted for every source.

Update, install and confirm:

bash
sudo apt update
sudo apt install plexmediaserver
systemctl status plexmediaserver --no-pager
curl -s http://127.0.0.1:32400/identity | grep -o 'version="[^"]*"'
text
version="1.43.5.11079-b3b13e506"

Anything at or above 1.43.3.10861 is fixed.

Docker users

If you run the official plexinc/pms-docker image, pull a current image and recreate the container rather than relying on an old pinned tag:

bash
docker pull plexinc/pms-docker:latest
docker compose up -d --force-recreate plex
curl -s http://127.0.0.1:32400/identity | grep -o 'version="[^"]*"'

Always confirm the running version through /identity after the restart. The image tag is not proof of the PMS version inside the container. The investigation steps above apply too; the data directory is whatever host path you mounted at /config.

Hardening After the Patch

Patching closes the bugs. It does not undo a token that already leaked.

  • Rotate tokens. Change your plex.tv password and use the option to sign out all connected devices. That invalidates existing device tokens, including any PlexOnlineToken read through CVE-2026-96651. Expect to sign clients back in and, if prompted, re-claim the server.
  • Do not forward 32400 raw. Prefer a VPN (WireGuard or Tailscale) or a reverse proxy that you patch and log. If you must expose PMS directly, limit the source addresses where you can.
  • Disable UPnP on the router so Plex, or anything else on the LAN, cannot open ports without you knowing.
  • Review shared users. Remove accounts that no longer need access. Each one holds a session token.
  • Alert on version drift. The underlying failure in most of these cases is not the bug, it is a server that stopped updating months ago.

Version drift alerting

The simplest check compares the running version against the public downloads API:

bash
#!/usr/bin/env bash
# /usr/local/bin/plex-version-check
set -euo pipefail
running=$(curl -fsS http://127.0.0.1:32400/identity | sed -n 's/.*version="\([^"]*\)".*/\1/p')
latest=$(curl -fsS https://plex.tv/api/downloads/5.json | python3 -I -c 'import json,sys; print(json.load(sys.stdin)["computer"]["Linux"]["version"])')
behind=0
dpkg --compare-versions "$running" lt "$latest" && behind=1
out=/var/lib/node_exporter/textfile_collector/plex.prom
cat > "$out.$$" <<EOF
# HELP plex_version_behind 1 if the running Plex Media Server is older than the latest public release
# TYPE plex_version_behind gauge
plex_version_behind{running="$running",latest="$latest"} $behind
EOF
mv "$out.$$" "$out"

Run it from a systemd timer or cron every few hours, point node_exporter’s --collector.textfile.directory at that path, and alert when plex_version_behind == 1 for more than a few days. If node_exporter already exposes apt metrics on the host, an alert on pending upgrades catches the same problem, with one caveat: a disabled source reports zero pending upgrades, which is exactly the failure described above. The /identity comparison does not have that blind spot.

These are not part of the KEV listing, but they belong on the same checklist.

  • CVE-2025-69414: a permanent access token can be retrieved via /myplex/account using a transient token. NVD 7.1 HIGH (CNA score 8.5). Affects PMS through 1.42.2.10156.
  • CVE-2025-69415: device-token access to /myplex/account is not aligned with the current device to account association. NVD 7.1 HIGH. Affects PMS through 1.42.2.10156.
  • CVE-2026-65696 (Overseerr): NVD describes an authorization bypass in the push subscription API in Overseerr through 1.35.0 that lets a user list, read and delete other users’ push subscriptions by userId, leaking email addresses and plexId values. The record is marked Deferred in NVD, with CNA scores from VulnCheck of 5.3 (CVSS 4.0) and 5.4 (CVSS 3.1). Check the project’s own advisory for the fixed release that applies to your deployment.

CISA’s catalog also still carries an older Plex entry, CVE-2020-5741 (remote code execution), added on 2023-03-10. Plex has been a KEV target before.

FAQ

Is my server safe if Remote Access is off? Safer, not safe. CVE-2026-96654 requires no authentication, and NVD notes the CVE-2026-96651 traversal is reachable by a LAN-adjacent attacker. A compromised device on your home network counts. Patch regardless.

Which version fixes CVE-2026-96656 and the related Plex CVEs? Plex Media Server 1.43.3.10861 fixes all five. The current release as of this writing is 1.43.5.11079.

Why does apt say NO_PUBKEY 0A05F1E6E7AFD573? You only have Plex’s 2015 key installed. The repo is signed by a subkey of PlexSign.v2. Install that key with the fingerprint check above and reference it with Signed-By.

Do I need to rebuild if I find nothing? No. Patch, rotate your plex.tv password and devices, and close direct exposure. Keep in mind that Plex logs rotate quickly, so a clean log check on a long-exposed server is reassuring but not conclusive. If the server sat unpatched and internet-facing for months, rotating tokens is not optional.

Conclusion

The individual Plex bugs look modest on paper: one needs admin, a couple are medium-severity SSRFs. Together they give an attacker the owner token and native code execution, which is why four of them landed in CISA KEV on 2026-10-20. For most self-hosters the fix is a version bump to 1.43.3.10861 or later. The harder part is noticing that the server stopped updating in the first place. Check /identity, run the read-only compromise checks before you upgrade, move the repo to the PlexSign.v2 key, rotate your tokens, and add a drift alert so the next advisory finds you already patched.