A 12-year-old flaw in PostgreSQL’s logical replication lets anyone with a backup account load arbitrary code into the database server, escalate to superuser, and install a backdoor that survives restarts. Cyera Research disclosed the vulnerability — CVE-2026-6471, dubbed PostGREShell — on September 1, 2026. The patch has been available since August 22. If you haven’t applied it, your database is still open.
What Broke, and Why It Took 12 Years to Find It
PostgreSQL’s logical decoding system converts write-ahead log records into change events that external tools can consume — it’s how Debezium, wal2json, and logical replication subscribers work. When a client creates a replication slot, it supplies the name of an output plugin to load. That plugin name is supposed to be a short identifier like pgoutput or test_decoding.
The problem: the replication protocol skips the same path-restriction check that the regular SQL LOAD command applies. The plugin name passes directly to dlopen() — the C library loader — without validation. Since dlopen() accepts full filesystem paths, an attacker with a REPLICATION-privileged account can hand the server a path to any compiled library on the system, or — on Windows — a UNC path to a file on a remote SMB server they control. No file write required.
The Attack Chain: Three Steps to Full Takeover
The exploit is straightforward once you have a REPLICATION credential, which backup tools and CDC pipelines routinely hold:
- Create a replication slot with a malicious plugin path instead of a legitimate plugin name.
- PostgreSQL loads the library via
dlopen(). The code runs inside the server process with no sandbox. - The malicious code escalates: it calls an internal PostgreSQL function to become bootstrap superuser, writes directly to the
pg_authidcatalog table to set all privilege flags, and installs hooks that bypass SQL-level permission checks.
On Windows, Step 1 alone enables remote code execution — the attacker hosts the DLL on an SMB server, and PostgreSQL fetches and loads it transparently.
Three Backdoors That Outlast Incident Response
PostGREShell isn’t a run-once exploit. The malicious plugin establishes three overlapping persistence mechanisms:
- pg_hba.conf rewrite — allows passwordless connections for any user and reloads the configuration immediately.
- shared_preload_libraries entry — copies itself to a stable path and registers for automatic loading into every new PostgreSQL backend after a restart.
- Catalog re-application — re-applies superuser status in
pg_authideven if an administrator manually reverts it.
Each mechanism covers the others. A compromised PostgreSQL server needs to be treated as fully untrusted until all three are cleared and a fresh instance is stood up from a known-good backup.
The CVSS Score Doesn’t Reflect Your Production Risk
PostgreSQL scored this at CVSS 7.2, classifying REPLICATION as “High Privileges Required.” That’s debatable. REPLICATION credentials are handed to backup agents, monitoring utilities, and CDC pipelines as a matter of routine — they’re not admin accounts, they’re operational ones. Treat a CVSS 7.2 that enables complete database takeover plus OS-level code execution as a 9.x when you’re communicating urgency to your team. Cyera Research found 114 malicious PostgreSQL plugins in VirusTotal already — trojans, miners, and reverse shells built for exactly this exploit path.
Who Is Actually Exposed
Any PostgreSQL deployment running versions 9.4 through 18.x (before the patched releases) with wal_level = logical is vulnerable. Logical WAL is no longer exotic — it’s required for logical replication subscribers, Change Data Capture, and cloud migrations. If you’re running Debezium, a logical replication pipeline, or any real-time sync setup, wal_level = logical is almost certainly set. This includes AWS RDS, Azure Database for PostgreSQL, Google Cloud SQL, and Supabase deployments.
Patch Now — And Read This Before You Do
Patched versions: PostgreSQL 18.6, 17.11, 16.15, 15.19, and 14.24. Before upgrading, run this query to avoid breaking third-party replication plugins:
-- Inventory your active plugins before patching
SELECT DISTINCT plugin FROM pg_replication_slots WHERE plugin IS NOT NULL;
-- Audit who holds REPLICATION privilege
SELECT rolname FROM pg_roles WHERE rolreplication = true;
The patch introduces output_plugin_libraries, which defaults to only pgoutput and test_decoding. If you use wal2json, decoderbufs, or pglogical, add them to this allowlist before upgrading or replication breaks silently. If you can’t patch immediately:
- Strip REPLICATION from any account that doesn’t strictly need it.
- Lock
pg_hba.confreplication entries to specific trusted IPs — never0.0.0.0/0. - Block outbound SMB (port 445) and NFS (port 2049) from database servers at the firewall.
- Monitor logs for replication slot creation with plugin names containing
/,\, or...
PostGREShell fits a recurring pattern: plugin loaders that predate modern security thinking, trusted through years of “it’s internal.” The same class hit Redis (RediShell, 13 years, CVSS 10.0), MySQL, MongoDB, and OpenVPN. Apply the patch, audit your replication accounts, and start treating REPLICATION credentials with the same care as superuser passwords.













