← Back to the cybersecurity blog

Twelve years in which a PostgreSQL replication account could load code on the server (CVE-2026-6471)

By Thilina Manana · COO, Director Técnico de Seguridad hard2bit y socio fundador · Published: 07 September 2026 · Updated: 07 September 2026
PostGREShell (CVE-2026-6471)

On 13 August the PostgreSQL project shipped a set of minor releases closing 28 security vulnerabilities. Several carried a CVSS of 8.8; the one making headlines nearly three weeks later scores 7.2. It is CVE-2026-6471, named PostGREShell by the researchers who found it, and it had been in the code since version 9.4 introduced logical decoding in 2014. What sets it apart from the rest of that release is the assumption it breaks: an account holding the REPLICATION attribute, the one handed to backup tools, standby servers and data connectors, could choose which library the server loaded and, through that choice, run code as the operating-system user PostgreSQL runs under.

The full chain was laid out by Cyera Research on 1 September: from code loading to permanent superuser and on to persistence through three mechanisms that cover for each other. As of 4 September there was no record of exploitation, no public proof of concept and no entry in CISA's KEV catalogue, as The Hacker News verified. The window is worth using.

At Hard2bit the PostgreSQL replication account has long sat on the non-human identity inventory we go through with clients: it was almost always created by someone who has since left, and it is used by tools that few people remember. This flaw moves that review to the top of the list.

What can be exploited, and under which conditions

The project advisory is terse: logical decoding did not check permissions. A user holding REPLICATION, without being superuser, picks the decoding plugin and through that choice makes the server dlopen() any file the operating-system account running PostgreSQL can see. Every version before 18.6, 17.11, 16.15, 15.19 and 14.24 is affected.

Two conditions have to hold at once. The first is an account with the REPLICATION attribute, which need not be superuser or administrator. The second is a server running with wal_level = logical, the setting that records changes as events external tools can read and which today underpins change data capture (CDC), Debezium, cloud migrations and real-time analytics. A client program wanting those changes creates a logical replication slot, a persistent read position on the change stream, and names the output plugin that should format the stream. That name went straight to the library loader.

How a malicious library reaches the loader depends on the platform. On Windows, network access is enough: the plugin name can be a UNC path, and the operating system resolves it over SMB from a server the attacker controls, without writing anything to the victim's disk. On Linux and macOS the same happens only where NFS automounting is active. Everywhere else, which covers most production Linux, Docker and Kubernetes deployments, the attacker must already have found a way to place a file on the server's disk.

The platform difference explains why the sources disagree on the privilege required. Cyera calls it a low-privilege account; the PostgreSQL project scored the flaw with Privileges Required set to High, and SUSE reproduced that assessment. Both readings hold. In PostgreSQL's permission model, REPLICATION is a privileged attribute. To the organisation that grants it to a backup tool or a Kafka connector, it is one more service credential, stored wherever the others are.

Timeline: from a February report to a September disclosure

  • 21 February 2026. Cyera sends the PostgreSQL security team a root-cause analysis, the affected versions and a Windows proof of concept, according to its own timeline. The team confirms the flaw six days later.
  • 13 August. Versions 18.6, 17.11, 16.15, 15.19 and 14.24 ship with the fix, listed among the 28 vulnerabilities in the release announcement. The text gives it no special prominence. Credit for the discovery goes to Vladimir Tokarev and Yu Kunpeng.
  • 20 August. Ubuntu publishes USN-8653-1 for 22.04, 24.04 and 26.04 LTS. As The Hacker News observes, the notice tells administrators to restart PostgreSQL after updating and does not mention the new configuration parameter.
  • 1 September. Cyera publishes the full analysis under the name PostGREShell. CSO Online and SecurityWeek cover it on 3 and 4 September.
  • 4 September. The Hacker News checks that day that the flaw is absent from the KEV catalogue, that no proof of concept exists in public repositories, and that the wal2json project has updated its documentation to explain how to register the plugin in the new allow-list.

One detail in the timeline tempers the alarm: the patch had been available for nineteen days when the analysis was published. Anyone tracking PostgreSQL minor releases was already protected without knowing it. The catch is that installing the patch can interrupt logical replication if no one prepares for it.

Why a replication account ends up as superuser

An output plugin is compiled code that PostgreSQL loads into its own process, and its initialisation function runs immediately with that process's permissions. The server already had a control for this risk, check_restricted_library_name(), which confines non-superusers to loading plugins from a single administrator-controlled directory, with no absolute paths and no directory traversal. The SQL LOAD command goes through that check. The replication path never called it, and the protocol parser accepted almost any character inside the plugin name, path separators included.

From there the problem stops being specific to PostgreSQL and becomes a property of any server that loads extensions. Access control lists, role permissions and row-level security live in the SQL layer. Code loaded through dlopen() shares the server's memory space and never crosses that layer.

In Cyera's test, the plugin writes directly to pg_authid, the catalogue that defines who is a superuser, and switches on every privilege flag for the account. The change survives restarts and, in the catalogue, is indistinguishable from a legitimate ALTER ROLE, so anyone reviewing pg_authid alone cannot tell how it was made. That privilege escalation then unlocks the usual superuser capabilities: running operating-system commands, reading files on the server and writing wherever the postgres user can.

The persistence described has three parts: rewriting pg_hba.conf to accept passwordless connections and reloading the configuration, copying itself to a stable path and registering in shared_preload_libraries so it loads into every new backend, and reapplying the superuser change should an administrator revert it. Whoever finds one of the three and undoes it still has two to discover.

Cyera places the flaw in a familiar family: a server that loads modules by name without validating the name. Redis with MODULE LOAD, MySQL and its shared libraries, MongoDB, OpenVPN and the SQLite JDBC driver have all been through variants of the same pattern. The report also points at why it keeps recurring: plugin-loading code tends to be written apart from the main security model, and the two paths are not always joined up.

Who is exposed, and how badly

Exposure comes down to three questions, and they need answering instance by instance rather than for the estate as a whole.

How many accounts hold REPLICATION, and for what?

Physical backup tools that use the streaming protocol (pg_basebackup, Barman in that mode), every standby server, every CDC connector (Debezium and its equivalents), every cloud migration service and a fair number of monitoring agents carry one, and they pile up over the years. A query against pg_roles filtered on rolreplication returns the list; the work is putting a name and an owner against each entry and stripping the attribute from those that do not need it. The Hard2bit piece on service accounts, tokens and API keys describes the same exercise for the rest of the credentials that belong to no person.

Is logical decoding switched on?

Without wal_level = logical there is no logical slot and no plugin load. Many instances have it enabled for a one-off need (a migration, a CDC trial) that ended long ago. If no consumer reads logical changes, setting it back to replica closes the route without waiting for the patch, at the cost of a restart.

What can the server reach outbound?

The most direct scenario is PostgreSQL on Windows able to open outbound SMB connections to the internet or to segments it does not control. Next comes a Linux host whose autofs can resolve network paths the attacker controls. Outside those two cases the flaw reverts to the two-step problem described above: the attacker first has to get a file written to the server's disk.

Two caveats about the estate. Managed services do not remove the work: Amazon RDS has fixed packages for all five branches, as The Hacker News reports, yet the replication account feeding a CDC connector still exists and remains the customer's responsibility. And branches before 14 receive no fix; the project also reminds users that PostgreSQL 14 stops receiving fixes on 12 November 2026, so any instance on 13 or earlier needs a migration rather than a minor update.

Detection: the trail it leaves

The server's EDR is unlikely to flag anything until the loaded plugin does something visible, and in the SQL layer the changes look legitimate. The trail lies in replication and in the catalogue itself. These are the indicators that deserve a SIEM rule or a scheduled query:

  • Plugin names containing path separators or traversal sequences in pg_replication_slots. The plugin column should hold only pgoutput, test_decoding or the third-party plugin the organisation installed knowingly.
  • CREATE_REPLICATION_SLOT requests from addresses that belong to neither the known replicas nor the known connectors. With log_connections enabled, the replication connection appears in the log together with its origin.
  • After patching, log lines reading ERROR: library "..." may not be used as an output plugin. According to the parameter documentation, that is how the new allow-list refuses a load. It may be a legitimate connector that was never registered or an attempted load; either way it needs a look.
  • Changes to pg_authid that set rolsuper on accounts that lacked it, edits to pg_hba.conf that loosen authentication, and new entries in shared_preload_libraries. All three should sit under integrity monitoring.
  • Outbound connections from the database server to ports 445 (SMB) and 2049 (NFS). Unless the server knowingly mounts storage or backups over NFS or SMB, they have no operational explanation.

If any of these signals appears, the priority is to assume the catalogue can no longer be trusted: compare pg_authid and pg_hba.conf against a known-good copy, review which libraries are loaded in the process, and rotate the credentials the database holds. It is the kind of investigation a threat hunting engagement runs across the catalogue and the file system together, because neither is enough on its own.

Patching without breaking replication

The fix does not apply the LOAD restriction to the replication path. Jacob Champion, who wrote the change, explains in the commit message that doing so would have forced every third-party plugin to be reinstalled under the extensions directory. Instead, the patch adds the output_plugin_libraries parameter, an allow-list of permitted plugins that by default contains only pgoutput and test_decoding, the two shipped with PostgreSQL. Any other plugin (wal2json, decoderbufs and in-house modules) stops loading after the update until an administrator adds it and reloads the configuration. The 18.6 release notes say so in plain terms.

So the order matters:

  • Before updating, inventory the plugins in use with SELECT DISTINCT plugin FROM pg_replication_slots WHERE plugin IS NOT NULL. The query lists only plugins that have loaded successfully at some point, so cross-check it with the data teams.
  • Update to 18.6, 17.11, 16.15, 15.19 or 14.24, or to the distribution's equivalent package. The Debian and Ubuntu advisories differ in detail: Debian warns that the fix requires configuration changes and names its wal2json and decoderbufs packages; Ubuntu's, as noted above, does not mention the parameter.
  • Add each third-party plugin to output_plugin_libraries and reload with pg_reload_conf(). No restart is needed.
  • When migrating from version 17 or later with pg_upgrade, set the parameter on the new cluster before running --check, because the check fails if the list does not permit the plugins used by the old cluster's slots.

One loose end remains on the development mailing list, as The Hacker News reports: pg_createsubscriber creates its slots with pgoutput without checking the parameter, so a --dry-run can pass and the real conversion fail afterwards if the server's list does not permit that plugin. On 4 September the patch was under review and not yet committed.

Until the update can be applied, the measures that cut exposure are the ones Cyera recommends, and none touches the application: strip REPLICATION from accounts that do not need it, restrict replication entries in pg_hba.conf to specific addresses (never 0.0.0.0/0), block outbound SMB and NFS from database servers at the firewall, and disable autofs where it is unused. All of it is hardening that should outlive the patch.

What to watch over the coming weeks

Three things are worth watching. First, whether CVE-2026-6471 enters the KEV catalogue or a public Linux proof of concept appears; the vulnerability management programme should keep the flaw under watch even though it is not yet in KEV and there is no public sign of exploitation, using the KEV, EPSS and SSVC criteria as the trigger for raising its priority. Second, scans against port 5432 left open to the internet, which still turns up in perimeter reviews. Third, and most important, the outcome of the REPLICATION account inventory: that inventory decides whether this flaw is a theoretical risk or an open door into the organisation.

Last week we wrote about Artifactory's join key, another case in which a credential created so that two components can talk to each other ends up granting administrator privileges. In PostgreSQL the same pattern sat unreviewed for twelve years. An account whose only job is to let two systems talk deserves the same least-privilege review as an administrator's, and in most of the estates Hard2bit audits it has yet to receive one.

This article combines technical information from the PostgreSQL project's public advisories with research published by Cyera Research and with checks carried out by The Hacker News, CSO Online and SecurityWeek, based on the information available at the date of publication. The queries, parameters and configuration measures described are indicative: every deployment should validate them in a test environment before applying them in production, and the allow-list of plugins must be tailored to each organisation's tooling. The exploitation status and the availability of proof-of-concept code may change.

Frequently asked questions

What is PostGREShell, and which PostgreSQL versions does it affect?

PostGREShell is the name Cyera Research gave to CVE-2026-6471, an authorisation flaw in PostgreSQL's logical decoding. It lets an account holding the REPLICATION attribute make the server load an arbitrary library and run code as the process's operating-system user. It has been present since version 9.4 (2014) and is fixed in 18.6, 17.11, 16.15, 15.19 and 14.24, released on 13 August 2026. Branches earlier than 14 receive no fix.

Is CVE-2026-6471 being exploited?

As of 4 September 2026 there was no record of exploitation: the flaw was not in CISA's KEV catalogue and The Hacker News found no proof-of-concept code in public repositories. Cyera mentions 114 malicious PostgreSQL plugins found on VirusTotal, but CSO Online notes that the research does not link them to this flaw. The picture can change, and the CVE belongs on a watch-list.

Why does the flaw score 7.2 if it leads to code execution and superuser?

The CVSS vector assigned by the PostgreSQL project rates the privileges required as High: an attacker needs an account with REPLICATION. On top of that, the server must be running wal_level = logical. Cyera describes it as a low-privilege account because in practice it is handed to backup tools and connectors. Once the conditions are met, the impact on confidentiality, integrity and availability is complete.

Is my PostgreSQL exposed if it runs on Linux or Kubernetes?

Less readily than on Windows. Outside Windows and a Linux host whose autofs can resolve foreign network paths, the attacker must already have placed a file on the server's disk, so the flaw works as the second step of an intrusion rather than the first. That lowers the urgency on a well-isolated Kubernetes cluster without removing it: a container with a writable shared volume, or an application with a file-upload vulnerability, supplies exactly that first step.

What changes after updating, and why can it break logical replication?

wal2json, decoderbufs and in-house plugins stop loading until they are registered in output_plugin_libraries and the configuration is reloaded, with no restart needed. In practice, a change-data-capture connector that worked the day before stops after the update with an error in the server log, and the data team notices before the security team does. Taking an inventory of plugins before updating avoids that surprise; the wal2json project already documents the step.

How do I check which accounts hold the REPLICATION attribute?

Query the pg_roles view and filter on rolreplication = true. The list usually includes accounts for the backup tool, the standby servers and the CDC connectors, plus, quite often, leftovers from old tests or migrations. Each one needs an owner and a purpose; those without an owner or without a purpose should lose the attribute. In pg_hba.conf, every account that keeps REPLICATION should be allowed to connect only from specific addresses.

What can I do if I cannot update PostgreSQL yet?

Cut back the two conditions the flaw depends on. On the accounts side: fewer users with REPLICATION and, for those that remain, pg_hba.conf entries locked to their source addresses. On the library side: egress filtering for ports 445 and 2049 and autofs switched off, so the server cannot fetch a file from outside. And if no tool consumes logical changes, setting wal_level back to replica removes the starting condition, at the cost of a restart.

Does this affect managed services such as Amazon RDS or Azure Database?

The provider updates the engine, but the responsibility is shared. A managed service's version numbering does not always match the project's, so check the provider's release notes to confirm that its package carries the CVE-2026-6471 fix, rather than assuming the latest available version includes it. And the REPLICATION accounts the customer created to feed connectors into Kafka or an analytics store are reviewed by the customer, not the provider.

Want to know what's actually exposed, and what to fix first?

Thirty minutes with a technical consultant — not a salesperson — is enough to get the problem in order: what's exposed right now, what gets fixed this week, what can wait, and what each stage costs. Penetration testing, security audits, vulnerability management, Microsoft 365, SOC/MDR and incident response.

If your situation is different, tell us anyway — we also take one-off questions on cybersecurity and regulatory compliance.

Based in Spain · Working across the EU and LATAM · ENS High · ISO 27001 · We usually reply in under 24 business hours