PostGREShell: PostgreSQL 12-year-old logical-decoding flaw turns a REPLICATION account into server code execution — CVE-2026-6471
Tags
- ops
- PostgreSQL
- CVE-2026-6471
- logical decoding
- REPLICATION attribute
- unguarded plugin load
- dlopen
- LoadLibrary
- SMB
- NFS
- pg_hba.conf
- shared_preload_libraries
- backdoor
- superuser escalation
- data breach
- database
- Cyera
- patching
Summary
On September 4, 2026, The Hacker News reported that PostgreSQL shipped its August 13, 2026 security update for a 12-year-old logical-decoding flaw that lets an account holding only the REPLICATION attribute execute arbitrary code as the OS user running the database server. The flaw, CVE-2026-6471 (CVSS 7.2, PostgreSQL's own scoring; SUSE reproduced the rating), has been present in every PostgreSQL version since logical decoding was introduced in 9.4 in 2014. Affected: versions before 18.6, 17.11, 16.15, 15.19, and 14.24; exploitation requires a REPLICATION-attribute account and a server running wal_level = logical.
Cyera Research (Vladimir Tokarev), who named the flaw PostGREShell in a September 1 write-up, showed the mechanics: the plugin name supplied in a CREATE_REPLICATION_SLOT command is passed directly to the library loader with no validation, no sanitization, and no call to the existing check_restricted_library_name() restriction that confines non-superusers to an admin-controlled plugin directory. The replication protocol's parser accepts almost any character inside the double-quoted plugin name — slashes, backslashes, ../ traversal, even Windows UNC paths — so a full filesystem path reaches dlopen() (Linux/macOS) or LoadLibrary() (Windows) exactly as typed. The entire bug is code execution via dlopen(); the fix is a two-line allowlist.
Delivery is platform-dependent, which is what makes it dangerous:
- Windows: fully remote, out of the box. Windows resolves UNC paths over SMB (port 445) transparently; PostgreSQL fetches the DLL from the attacker's own SMB server, maps it into the database process, and _PG_init() runs. Nothing is placed on the target filesystem — the exploit fits in three lines of Python.
- Linux/macOS with NFS automounting (default on pre-Catalina macOS; RHEL/CentOS/Rocky with autofs): ../ traversal to /net/<host>/... triggers an automatic NFS mount (port 2049) from the attacker's server.
- Everything else (vanilla Linux, Docker, K8s): no network fetch — the attacker needs an existing way to write a file to the server's disk, then ../ traversal loads the local .so.
Once code runs in the database backend, the C-level trust model does the rest: the attacker's plugin calls an internal function to become the bootstrap superuser for the session, writes directly to pg_authid (bypassing the SQL executor, so no ACL check ever fires), and flips every privilege flag. The change survives restarts and looks identical to a normal ALTER ROLE in the catalog. With superuser: read every table in every database, COPY ... TO PROGRAM OS commands, pg_read_file() on /etc/shadow and private keys, lo_export() file writes — full server compromise and a pivot point.
The PoC also installs three overlapping persistence mechanisms: it rewrites pg_hba.conf to allow anyone to connect as anyone without a password and reloads it, copies itself to a stable location and registers in shared_preload_libraries so it reloads into every new backend after restart, and re-applies the superuser change even if an admin reverts it — an admin who fixes one backdoor still has two more to find.
Cyera's threat hunt across VirusTotal found 114 malicious PostgreSQL plugins already in the wild — trojans, cryptocurrency miners, and reverse shells — showing the attack surface is not theoretical.
The fix and what it breaks
The fix (shipped August 13, 2026, credited to Jacob Champion) adds a new server parameter output_plugin_libraries: a whitelist of libraries allowed to load as logical-decoding output plugins, defaulting to 'pgoutput, test_decoding'. The PostgreSQL project rejected simply applying the existing LOAD restriction to the replication path: per Champion's commit message, doing so "would retroactively require all third-party output plugins to be installed under the $libdir/plugins directory."
Operational fallout: after updating, any installation using a non-default output plugin — wal2json, decoderbufs, and the like — will have logical decoding refused until an administrator adds the library to output_plugin_libraries and reloads the server. Failed loads log ERROR: library "..." may not be used as an output plugin with a hint naming the setting.
- Amazon RDS ships fixed packages for all five branches.
- Debian's advisory explicitly warns the upstream fix "requires additional changes to the configuration if some extensions are used," naming its wal2json and decoderbufs packages.
- Ubuntu USN-8653-1 (shipped August 20, 2026, for 22.04 / 24.04 / 26.04 LTS) made no mention of the parameter and told administrators only to restart PostgreSQL — distributions have since been reconciling.
- The PostgreSQL advisory covers supported branches 14 through 18 only; PostgreSQL 14 stops receiving fixes on November 12, 2026 — 9.4–13.x deployments have no patch path.
Affected scope
- Versions: every release from 9.4 (2014) through 18.x, before the August 13, 2026 update; Cyera confirmed it on 18.2.
- Preconditions: an account with the
REPLICATIONattribute (backup tools, standby servers, CDC pipelines, monitoring systems — "operational plumbing" treated as low-risk) andwal_level = logical, which is standard for CDC / Debezium / cloud replication / real-time analytics. - Universal across platforms; only the delivery path differs (SMB / NFS-automount / local-file-write).
- Blast radius: the world's #1 open-source database and fourth-most popular overall; the engine behind AWS RDS, Azure Database, Google Cloud SQL, Supabase, and Neon; used in production by 39,000+ verified companies (including Netflix, Instagram, Spotify, Uber). Runs financial transactions, medical records, government infrastructure, SaaS platforms, and AI/ML pipelines.
Mitigations and response
- Patch immediately to 18.6 / 17.11 / 16.15 / 15.19 / 14.24 (or vendor/RDS fixed packages).
- After patching, audit logical decoding before it breaks: enumerate which output plugins each instance uses; add every legitimate third-party plugin (
wal2json,decoderbufs, ...) tooutput_plugin_librariesand reload — otherwise CDC/replication pipelines will refuse to start. - Audit
REPLICATIONaccounts on every instance: remove the attribute from any account that doesn't strictly need it; for the rest, lock downpg_hba.confso replication connects only from known, trusted IPs — never0.0.0.0/0. - Block outbound SMB (445) and NFS (2049) from database servers at the firewall — this eliminates the fully-remote Windows path and the NFS-automount path on Linux/macOS; disable
autofswhere present. - Hunt the in-the-wild payload: Cyera counted 114 malicious PostgreSQL plugins on VirusTotal (trojans, miners, reverse shells) — check loaded shared libraries against inventory, and audit
pg_authidfor privilege flips that look like routineALTER ROLEbut have no administrative provenance.
Detection / defensive heuristics
pg_hba.confmodification + immediate reload from a non-admin session (the backdoor's first persistence step) — alert on config writes outside the DBA workflow.shared_preload_librariesgaining an entry not in the known extension inventory; a new.soin the plugins directory with no corresponding extension.- Outbound SMB 445 / NFS 2049 connections from a PostgreSQL host — a database server initiating an SMB session is not normal behavior; this is the fully-remote exploit's tell.
ERROR: library "..." may not be used as an output pluginin server logs after the patch: a legitimate misconfiguration, or an attempted load that was just blocked — either way, correlate with the source connection.- Superuser privilege flips without an administrative audit trail in
pg_authid; cross-checkALTER ROLEactivity against change-management records. - Recurring/automated re-application of superuser flags after an admin reverts them — the third persistence mechanism.
Why this matters
- The unguarded back entrance to a fortress everyone assumed was locked. A vulnerability class keeps recurring — a server loads plugins, the plugin name isn't validated, and an attacker abuses it to run code. The poster child is Redis (
MODULE LOADpowering multiple botnet campaigns; HeadCrab alone infected 1,200+ Redis servers to mine cryptocurrency; "RediShell" CVE-2025-49844, CVSS 10.0, sat exposed ~13 years across ~330,000 internet-facing instances). The same pattern has hit OpenVPN (plugins loadable from any directory), MySQL (attacker-controlled shared libraries; also MariaDB and Percona), MongoDB (uncontrolleddlopen()search path), and SQLite JDBC (arbitrary extension loading via a malicious JDBC URL). - It ships wide and sits quiet. The flaw predates logical decoding becoming standard production plumbing; 12 years unguarded with the REPLICATION credential — "low-risk operational plumbing" per PostgreSQL's own docs — as the only precondition. 114 malicious plugins already in the wild proves the exploitation pipeline exists now, not after patching.
- The fix has an operational cost.
output_plugin_librariesdefaulting topgoutput, test_decodingmeans every CDC / Debezium / migration / analytics pipeline on a non-default plugin breaks until manually allowlisted — patching creates a two-track problem: unpatched hosts are exploitable, freshly-patched hosts silently stop replicating.
Assessment limits
- CVSS 7.2 (PostgreSQL / SUSE) reflects the
REPLICATION-attribute requirement andwal_level = logicalprecondition; the realistic severity is higher for environments where replication accounts are broadly trusted, because the exploit chain then ends in superuser + OS-level code execution + persistent backdoor. - No confirmed in-the-wild exploitation of CVE-2026-6471 itself is reported as of September 4, 2026; the 114 VirusTotal plugins are malicious artifacts consistent with the class, not confirmed live intrusions.
- No patch path for EOL branches 9.4–13 — the advisory covers 14–18 only, and 14 itself ends support November 12, 2026.
- PostGREShell is Cyera's naming; the flaw is CVE-2026-6471 and the fix is the
output_plugin_librariesparameter (August 13, 2026 release).
Related pages
- Sangoma Switchvox / Splunk PostgreSQL-adjacent KEV entries (context for PostgreSQL-ecosystem exploitation in CISA KEV)
- Plex "update immediately" advisory context (same September 2026 patch-window urgency)
Sources
- The Hacker News — "PostgreSQL Fixes 12-Year-Old Logical Decoding Flaw Enabling Replication-Role Code Execution" (published 2026-09-04): https://thehackernews.com/2026/09/postgresql-fixes-12-year-old-logical.html
- Cyera Research — "PostGREShell: The database powering much of the internet had an open door for 12 years" (Vladimir Tokarev, September 1, 2026 write-up): https://www.cyera.com/research/postgreshell-the-database-powering-much-of-the-internet-had-an-open-door-for-12-years
- PostgreSQL Global Development Group — 18.6 release notes / security advisory (fix:
output_plugin_libraries; credited to Jacob Champion; reported by Vladimir Tokarev and Yu Kunpeng)