SevyDevy

Guide · Backend

Plex's October 2026 Plex2Shell Bugs Explained: How to Patch and Check

19 min readUpdated By Saket Bhatnagar

Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.

In short

  • Plex2Shell is the name a security researcher gave to four bugs in Plex Media Server that chain together. Chained, they let an attacker on the internet run commands on your server without logging in.
  • The CVE ids are CVE-2026-96652, CVE-2026-96654, CVE-2026-96655 and CVE-2026-96656. CVE ids are public bug numbers. Plex fixed all four in version 1.43.3.10861.
  • The fix is a Plex update, nothing else. If your server is older than 1.43.3.10861 and reachable from the internet, Plex says to treat it as possibly compromised.
  • Exploitation was first seen on 17 October 2026, one day after the write-up went public, on a honeypot run by the boredhackerblog author. Plex's 19 October update reports widespread attacks dropping a cryptominer and proxy software.
  • Engineers also get the four bug classes, each shown with our own safe code. They are a server-side request forgery, trusting requests from 127.0.0.1, an unanchored prefix match, and a file write into a folder that loads code.

What goes wrong when the vulnerability is in Plex itself?

With Plex2Shell, the broken code sits inside Plex Media Server, so updating your other apps or your router does not fix it. Only updating Plex closes the hole.

Plex Media Server is the program that stores your media library and streams it to your TV, phone and browser. Many people open it to the internet so they can watch from anywhere.

Picture a common setup. A family in Pune runs Plex on a small home server to stream their photos and films while travelling. They forwarded one port on the router so it works away from home.

The setup is made up, but the risk is real. That one open port is all an unpatched server needs to be found, exploited and turned into a miner. This guide follows that server from alert to clean fix.

Plex2Shell is the chain that makes this possible, and the exact phrase plex2shell is what people are searching after the news. You will learn what the four bugs are, how to patch, and how to check for a break-in.

Which words do you need before reading about Plex2Shell?

You need six terms. Each gets a plain meaning and its place in the story.

  • Remote code execution (RCE): an attacker on the internet makes your server run commands they pick. Here those commands run as the Plex service account.
  • Unauthenticated: no login, password or valid token is needed. Per the researcher and the CVE record, the first bug only checks that a token header is present, not that it is real.
  • Server-side request forgery (SSRF): you trick a server into making a network request for you, to an address you choose. The server becomes your messenger.
  • Loopback (127.0.0.1): the address a machine uses to talk to itself. Programs often trust loopback traffic because it should only come from the same machine.
  • Admin token: a secret string that proves you are the server owner. Anything holding it can change server settings.
  • Codecs folder: a directory where Plex keeps media helper libraries (codec files). Per the researcher and the CVE record, Plex loads every .so file in it when it starts converting video, a step called transcoding.

What is Plex2Shell (CVE-2026-96652, 96654, 96655 and 96656)?

Plex2Shell is a chain of four Plex Media Server bugs that together let an unauthenticated attacker run code on the server. A security researcher, credited as Zach Main in the CVE records, reported them and named the chain in a write-up on zmain.info.

None of the four is full remote code execution on its own. Chained in order, they take an attacker from no access to running a program as the Plex user. The official Plex advisory describes each one in one line.

The four chained CVEs, with the one-line summary from the Plex advisory (19 October 2026) and the CVSS v4.0 score from each CVE record. CVSS is a 0 to 10 severity score.
CVE idWhat the advisory calls itCVSS v4.0
CVE-2026-96652Unauthenticated SSRF in the player timeline endpoint5.3 medium
CVE-2026-96654Access to internal agent functions over the loopback interface6.9 medium
CVE-2026-96655Disclosure of the server owner's admin token5.3 medium
CVE-2026-96656Arbitrary file write to the Codecs directory via transcoder preferences8.6 high

The individual scores look modest, yet the chain is severe. The researcher rates the full chain 9.8 out of 10 on the older CVSS v3.1 scale. That gap is normal: each bug is small, the chain is not.

A fifth bug, CVE-2026-96651, is a path traversal that lets an attacker read files on the server. It is fixed in the same build, but Plex and the researcher do not list it in the chain.

Plex is closed source, so we cannot verify the internals. Every mechanism detail below is attributed to the researcher write-up or the Plex advisory, and we never ran the proof of concept. We teach the bug classes with our own safe code.

How do four small bugs chain into remote code execution?

Each bug hands the attacker one more capability, and the next bug needs exactly that capability. Miss any link and the chain breaks. The researcher describes five stages.

The attacker starts outside with no access. The SSRF gets the server to make a request to itself. That self-request is trusted because it comes from loopback, which opens an internal plugin interface. An injection flaw there then lets the attacker call internal plugin functions.

A weak check on one of those outbound calls then leaks the owner's admin token. With the token, the attacker changes a transcoder setting so a later video conversion writes a file into the Codecs folder. Plex loads that file as code, and it runs.

The Plex2Shell chain, stage by stage

Notice how each box only works because the one before it succeeded. The first request is blind: the attacker never sees the reply. The token leaks later, when the server itself sends it outward.

Diagram connections:

  • Attacker on internet to 1. SSRF (Send one request)
  • 1. SSRF to 2. Loopback trusted (Call to 127.0.0.1)
  • 2. Loopback trusted to 3. Admin token leaks (Reach plugin API)
  • 3. Admin token leaks to 4. File write to Codecs (Use the token)
  • 4. File write to Codecs to 5. Code runs as plex (Trigger transcode)
  • Attacker on internet: No login, no valid token
  • 1. SSRF: Server is made to call itself
  • 2. Loopback trusted: Plugin functions become callable
  • 3. Admin token leaks: Prefix check sends it outward
  • 4. File write to Codecs: Transcoder preference abused
  • 5. Code runs as plex: Codec file loaded at transcode

What is an SSRF, and why does it start the chain?

A server-side request forgery makes a server send a network request to an address you choose. The server, not you, makes the call. That matters when the server can reach places you cannot.

Plex listens on port 32400 and is often exposed to the internet, says the researcher. Per the researcher and the CVE record, the first bug accepts a request as long as a token header exists. It never checks the token is valid, so no login is needed.

Here is the bug class in our own tiny server. One endpoint runs a privileged action only for callers from 127.0.0.1. Another sends a blind POST to any callback URL, as long as a token header is present.

python
# Our own toy server, not Plex. The network is simulated by a function call.
# /admin trusts the caller address; /notify sends a blind POST to any URL.
from urllib.parse import urlsplit

audit_log = []

def handle(path, client_addr, headers, callback=None):
    if path == "/admin/enable-debug":
        if client_addr == "127.0.0.1":           # trust by source address: risky
            audit_log.append("debug mode ON")
            return "done"
        return "denied"
    if path == "/notify":
        if "X-Token" not in headers:             # header must exist; value never checked
            return "no token header"
        post(callback)                           # blind SSRF: reply is thrown away
        return "ok"
    return "not found"

def post(url):
    # stands in for an HTTP client; a call to 127.0.0.1 arrives from 127.0.0.1
    parts = urlsplit(url)
    if parts.hostname == "127.0.0.1":
        handle(parts.path, "127.0.0.1", {})

outsider = "203.0.113.7"
print(handle("/admin/enable-debug", outsider, {}))
print(handle("/notify", outsider, {"X-Token": "anything"},
             callback="http://127.0.0.1:32400/admin/enable-debug"))
print(audit_log)

Running it prints denied, then ok, then a log showing debug mode ON. The outsider was refused directly, yet the action ran through the notify endpoint. The outsider only ever saw the word ok.

That matches the researcher's description of Plex: the SSRF is blind, so the attacker never sees the reply. It is still enough to make the server act on a trusted local call. Our tests/02 script repeats this over real sockets.

Why is trusting a request from 127.0.0.1 risky?

Programs trust loopback traffic because it should only come from the same machine. An SSRF breaks that assumption: now an outsider can make the server produce genuine loopback requests.

In Plex, the researcher says requests from 127.0.0.1 skip authentication, which exposes an internal plugin interface. The SSRF from the first stage is what gives the attacker a real loopback origin to reach it.

The lesson is general. Source address is not identity. Anyone who can make your server call itself can impersonate a local, trusted client. Loopback should never be your only check for a sensitive action.

How does an unanchored 127.0.0.1 prefix match leak a secret?

The token-leak step rests on a string check that is too loose. The researcher says Plex attaches the owner's admin token to an outbound request when the target URL starts with http://127.0.0.1.

A plain starts-with test is unanchored: it only looks at the front of the string and ignores the rest. So a hostname like 127.0.0.1.attacker.example also passes, and the token is sent to the attacker's host.

This is a famous mistake, so we show it with our own code, not Plex code. The string starts with 127.0.0.1, yet it is not the loopback address at all.

python
import ipaddress
from urllib.parse import urlsplit

def naive_is_local(url):
    # the loose pattern: only looks at the front of the string
    return url.find("http://127.0.0.1") == 0

def is_loopback_url(url):
    host = urlsplit(url).hostname          # pull out just the host
    try:
        return host is not None and ipaddress.ip_address(host).is_loopback
    except ValueError:
        return False                       # a name, not an IP, so not loopback

for u in ["http://127.0.0.1:32400/x",
          "http://127.0.0.1.attacker.example/x",
          "http://[email protected]/x"]:
    print(naive_is_local(u), is_loopback_url(u), urlsplit(u).hostname)

Pause and predict before you read on. Of the three URLs, which one is really the loopback address, and which two only look like it at the start?

We ran it in tests/01_prefix_match.py. The output shows the problem clearly.

text
True True 127.0.0.1
True False 127.0.0.1.attacker.example
True False attacker.example

The naive check says all three are local. The safe check parses the host and asks the ipaddress library whether it is really a loopback address. Only the first line is. The other two are attacker hosts.

The second case hides the attacker host after a dot. The third hides it after an @ sign, so the real host is attacker.example while the text still begins with 127.0.0.1. Parsing beats string matching every time.

How does a file write into a codec folder become code execution?

The last bug lets the attacker, now holding the admin token, write a file where Plex will later load it as code. The Plex advisory calls it an arbitrary file write to the Codecs directory through transcoder preferences.

The researcher explains the mechanism. A transcoder preference is passed to the video encoder, and an encoder option can write output to a path the caller picks, inside the Codecs folder. When Plex next transcodes, it loads codec files from that folder.

So two weak spots meet. One lets you write a file into a sensitive folder. The other loads every .so file in that folder as code without checking it. Either alone is a bug; together they are code execution.

Why a file in the wrong folder runs

Notice the folder does double duty: it is both a write target and a place code is loaded from. Keeping those two jobs apart is the fix.

Diagram connections:

  • Transcoder preference to Video encoder (Option sets output path)
  • Video encoder to Codecs folder (Writes file)
  • Codecs folder to Transcoder startup (Next transcode)
  • Transcoder startup to Attacker code runs (File loaded as code)
  • Transcoder preference: Set with the stolen token
  • Video encoder: Writes output to chosen path
  • Codecs folder: Now holds attacker file
  • Transcoder startup: Loads every .so in the folder
  • Attacker code runs: As the plex user

We show the class with a toy loader, not Plex. It runs every file in a folder, and a separate writer is supposed to keep files out of that folder. The naive writer fails; a safe one refuses.

python
from pathlib import Path

OUT = Path("/tmp/transcode-out").resolve()   # where output should stay

def safe_output_path(user_path):
    p = (OUT / user_path).resolve()          # resolve .. and symlinks first
    if not p.is_relative_to(OUT):            # must stay inside OUT
        raise ValueError("refused: " + user_path)
    return p

for name in ["frame-0001.yuv", "../Codecs/extra.so", "/var/lib/other/extra.so"]:
    try:
        print("ok", safe_output_path(name))
    except ValueError as e:
        print(e)

Running tests/snippet_c_writer.py, the normal name is accepted. The two paths that try to escape into another folder are both refused. The fix resolves the path, then checks it still sits inside the allowed folder.

The deeper fix is to never load code from a folder that untrusted input can write to. Load only from a read-only location, and check each file by a known hash before running it, as our tests/03 loader shows.

How do you check whether your Plex server is patched?

Check the exact version your server runs, and compare it as numbers, not text. Plex says 1.43.3.10861 and later are safe. Anything older is affected.

The simplest way: open Plex Web, go to Settings, then General, and read the version. On Linux you can also ask the package manager. The build number is the part that matters.

Comparing versions as plain text is a common bug. On Debian or Ubuntu, let the package tools compare for you. On other systems, split the version into numbers and compare those.

bash
# Debian or Ubuntu: read the installed version, then let dpkg compare it
dpkg-query -W -f='${Version}\n' plexmediaserver
dpkg --compare-versions "$(dpkg-query -W -f='${Version}' plexmediaserver)" ge 1.43.3.10861 \
  && echo "patched" || echo "NOT patched"

We tested the compare step with dpkg on Ubuntu 24.04 using an empty stand-in package. It correctly called 1.43.3.10828 not patched and 1.43.3.10861 patched. The matching Python number check is in tests/04.

python
FIXED = (1, 43, 3, 10861)

def is_patched(version):
    core = version.split("-")[0]                         # drop any build suffix
    return tuple(int(x) for x in core.split(".")) >= FIXED

for v in ["1.43.3.10828", "1.43.3.10861", "1.43.10.100"]:
    print(v, "string says", v >= "1.43.3.10861",
          "| numbers say", is_patched(v))

The output shows text comparison getting 1.43.10.100 wrong, while the number check gets it right. Expect: string says False but numbers say True for that line. Always compare versions as numbers.

How do you check a Plex server for compromise?

If your server was old and internet-facing, Plex says to assume it may be compromised and look for signs. The reports list a few clear indicators. We quote only what the sources state.

The Plex advisory names these signs. The names and addresses come straight from its 19 October update.

  • Processes started by Plex that you do not recognise, with names like myawesomeproxy, mylovelyminer or x12345, per the Plex advisory.
  • Unfamiliar .so or .dll files in the Plex Codecs folder, per the Plex advisory.
  • Outbound connections to proxystream.st, or steady high CPU use while nothing is playing, per the Plex advisory.

The boredhackerblog author, who describes themselves as an infosec person and Plex user, ran the honeypot. Their report adds file hashes and attacker addresses, and warns that attackers may change their tools. So matching these exact names may miss a variant. Check behaviour too.

Here are read-only checks. They only look; they change nothing. The Plex data folder on Debian or Ubuntu is under /var/lib/plexmediaserver, per the Plex support article on the data directory. Adjust the path for your platform.

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

# 1. recently changed code files in the Codecs folder, newest first
find "$DATA/Codecs" -type f \( -name '*.so' -o -name '*.dll' \) \
  -printf '%TY-%Tm-%Td  %p\n' | sort -r

# 2. quick first pass only: files changed on or after the PoC date
#    (check 1 lists everything; CVE details were public from 23 Sep)
find "$DATA/Codecs" -type f -newermt 2026-10-16 -print

# 3. transcoder options someone may have changed
grep -io 'Transcoder[A-Za-z0-9]*Options="[^"]*"' "$DATA/Preferences.xml"

# 4. process names from the Plex advisory, plus xmrig, the miner
#    named in the honeypot report's file list and in news reports
ps -eo user,pid,etime,comm | grep -E 'myawesomeproxy|mylovelyminer|x12345|xmrig'

We ran these against a fake data folder in tests/05, with a harmless file dated 17 October and a planted transcoder option. The find and grep steps surfaced exactly the recent file and the changed setting, as intended.

On Windows the settings live in the registry under HKEY_CURRENT_USER, Software, Plex, Inc., Plex Media Server. On macOS they sit in com.plexapp.plexmediaserver.plist under Library, Preferences. Both come from the Plex support article on hidden server settings.

On those systems, look for transcoder options you did not set in those settings, review the Codecs folder, and watch for the same process names and outbound connections.

How do you patch and recover your Plex server?

Update to 1.43.3.10861 or newer, then, if there is any sign of compromise, rebuild rather than trust the old data. Plex lists the steps in its advisory; the table sums them up.

Patch and recovery steps from the Plex advisory, as of 23 October 2026. Updating is the only complete fix; the recovery steps matter only if the server may already be hit.
StepWhat to doWhy
Update PlexInstall 1.43.3.10861 or newer from Plex: auto-update, the Downloads page, or your platform package.The fix is in Plex itself.
Prefer a clean rebuildIf compromise cannot be ruled out, rebuild from a clean install, not the old data directory.A dropped file may survive an update.
At minimum, clear CodecsDelete everything in the Codecs folder and check Preferences.xml for transcoder options you did not set.That is where the attacker writes.
Rotate accessSign out of all devices in your Plex account settings and change your Plex password.The owner token may have leaked.
Assume wider exposureTreat anything the Plex service account could reach as potentially exposed: files, mounted drives and stored credentials. Rotate those secrets too.Attacker code ran with Plex's access.
Reduce exposureIf you do not need remote access, turn it off under Settings, Remote Access, and avoid forwarding port 32400.Fewer servers are reachable to attack.

On Debian or Ubuntu, download the .deb package and install it with sudo dpkg -i, using the filename you downloaded, per the Plex advisory. On Fedora or similar, install the .rpm package. Then confirm the new version under Settings, General.

The order matters when you fear a break-in. Updating stops the hole, but a file the attacker already dropped can survive an update. That is why Plex pushes a clean rebuild rather than reusing the old data directory.

One more point on timing. The researcher reported the bugs on 27 July 2026. Plex made 1.43.3.10861 available to everyone on 4 August, and the CVEs were published on 23 September. Servers updated since August were not affected by the October attacks.

How do you explain Plex2Shell in a system design interview?

Use it to show how small, low-severity bugs chain into a critical one, and how you would reduce blast radius. Frame it in a few clear steps.

  1. Name the chain, not one bug

    Say four medium bugs chain into unauthenticated RCE. No single bug is critical; the composition is. Scoring each bug alone understates the risk.

  2. Call out the trust boundary mistake

    The core error is trusting loopback as identity. An SSRF turns an outsider into a trusted local caller, so source address must never be the only check.

  3. Point at the loose string check

    A starts-with test on a URL leaked a secret. Decide trust on a parsed host or an exact allowlisted origin, never on how a string begins.

  4. Separate write paths from load paths

    Code ran because one folder was both writable and a load source. Load code only from read-only locations, and verify files before loading.

  5. Reduce exposure and plan recovery

    Say you would avoid exposing the service directly, rotate the leaked credential, and rebuild clean rather than patch over a possible break-in.

Questions people ask

What is Plex2Shell in one sentence?
Plex2Shell is a chain of four Plex Media Server bugs, found by a security researcher credited as Zach Main in the CVE records. Chained, they let an unauthenticated attacker on the internet run code on your server. The bugs are CVE-2026-96652, CVE-2026-96654, CVE-2026-96655 and CVE-2026-96656. Plex fixed all four in version 1.43.3.10861, available to everyone from 4 August 2026.
Which Plex version fixes Plex2Shell?
Plex Media Server 1.43.3.10861 and later are not affected, per the Plex advisory. Anything older is vulnerable. Watch out for 1.43.3.10828, an older release that starts with the same numbers but is not fixed. Compare the full version, including the build number after the last dot, as numbers rather than as text.
Is my Plex server affected if it is not on the internet?
The chain is remote and unauthenticated, so an internet-facing server is the main target. A server only reachable on your home network is far harder to attack. Even so, update to 1.43.3.10861 or newer, because other devices on your network could be used to reach it, and patching is the only complete fix.
How do I know if my Plex server was already hacked?
Plex lists a few signs. Look for processes Plex started that you do not recognise, such as myawesomeproxy, mylovelyminer or x12345. Look for unfamiliar .so or .dll files in the Codecs folder. Watch for outbound connections to proxystream.st or high CPU while nothing plays. If you see any, rebuild from a clean install rather than trusting the old data.
Do I need to change my Plex password after patching?
If your server may have been compromised, yes. One of the bugs can leak the owner's admin token, so Plex advises signing out of all devices in your account settings and changing your password. On a server that was never exposed or was patched before 16 October 2026, this is a sensible precaution rather than a requirement.
Was Plex2Shell actually exploited in the wild?
Yes. The Plex advisory update of 19 October 2026 reports active, widespread exploitation. It was first seen on 17 October, one day after the public write-up, on a honeypot run by the boredhackerblog author. News reports describe a cryptominer and proxy software dropped on hit servers. Patched servers were not at risk from this activity.

Sources and further reading

Practise this with Lala

Practise