PostgreSQL Extension pglogical: CVE-2026-50736 Superuser Escalation
Four flaws hit pglogical, a PostgreSQL add-on. The side receiving replicated data runs at the top privilege, so whoever sends it can take over. Fixed in 2.4.8.
Table of contents
Four flaws hit pglogical, a PostgreSQL add-on. The side receiving replicated data runs at the top privilege, so whoever sends it can take over. Fixed in 2.4.8.
Four vulnerabilities have been published at once in pglogical, an add-on component (an "extension") installed into the PostgreSQL database software. They are CVE-2026-50736, CVE-2026-50737, CVE-2026-50735 and CVE-2026-50738, all registered in the US National Vulnerability Database (NVD) at 19:17 UTC on July 28, 2026.
First, let us separate out the point most likely to be confused. This is not a vulnerability in PostgreSQL itself. PostgreSQL runs on its own, but it offers a mechanism for installing add-on components called extensions when you want extra capabilities. pglogical is one of those extensions, and it handles replication, which means feeding the changes made in one database into another. All four issues occur inside that extension. Keeping PostgreSQL itself up to date does not cover them if pglogical is installed.
All four also share a single core. It is the design decision that the process receiving the data runs with the highest privilege the database has. The upstream release pglogical 2.4.8 shipped at 18:10 UTC on the same day and fixes all four. As described below, however, upgrading to 2.4.8 alone does not change the default behavior of running with superuser privilege.
The four published issues
The CVE numbers were assigned by EnterpriseDB (EDB), which distributes pglogical. The CVSS values (the common scale that rates severity from 0 to 10) shown below were supplied by EDB in the CVE records. NVD's own assessment has not been entered yet.
| CVE | Issue | CVSS 4.0 (assigned by EDB) | Class | Fixed in |
|---|---|---|---|---|
| CVE-2026-50736 | Commands sent down the replication queue run as superuser on the subscriber | 9.0 CRITICAL | CWE-89 | 2.4.8 |
| CVE-2026-50737 | Default expressions evaluated for rows with missing columns run as superuser | 9.0 CRITICAL | CWE-250 | 2.4.8 |
| CVE-2026-50738 | Use-after-free (worst case: arbitrary code execution) | 7.7 HIGH | CWE-416 | 2.4.8 |
| CVE-2026-50735 | Missing length validation causes out-of-bounds read (disclosure or crash) | 6.1 MEDIUM | CWE-125 | 2.4.8 |
The affected range is identical for all four. EDB's records list every version of the pglogical 2 series below 2.4.8. The reporter is also the same for all four: Mehmet Ince (@mdisec), co-founder and CTO of the threat intelligence company PRODAFT. According to his own site he has published more than 300 vulnerabilities since 2008, and his recent work has moved through extensions and tools around PostgreSQL.
Only someone who can act as the publisher has a way in
These four are not usable by an unrelated stranger somewhere out on the internet. The people who can reach them are those who can act as the server that sends the data, or those who have already taken over the sending server. Replication starts from an arrangement agreed in advance between sender and receiver, so only someone standing on one side of that arrangement has a way in. In concrete terms: an internal engineer who can point replication at a destination of their choosing, a customer of a provider that offers replication, and an attacker who has already broken into the sending server.
Whoever reaches the publisher side of a logical replication link then feeds commands disguised as replicated data into the receiving database, where they execute with the highest privilege. This is not a matter of altering records one at a time. It hands over the privilege to do anything at all to the receiving database. Another customer's tables sitting on the same server, administrative data including password hashes, unencrypted personal information: everything that privilege reaches is in scope.
Whether the receiver's superuser privilege amounts to a real loss depends heavily on whether the environment is single-party or shared. If you run both the sender and the receiver yourself, you already hold administrative rights on both, so there is little new to lose. The trouble comes when the sender and the receiver have different administrators. In a company that splits databases by department and replicates between them, in a group that distributes master data across affiliated companies, or at a provider that offers replication to multiple customers, a compromise on one side leads directly to the highest privilege on the other. Put from a defender's point of view: you did not trust the other party's database, yet you were receiving their data with a process that held superuser privilege.
What "the receiving side runs as superuser" actually means
CVE-2026-50736 and CVE-2026-50737 have completely different entry points. The first is a mechanism built into the replication path for carrying commands; the second is the calculation of default values when a row arrives with columns missing. Yet the reason both are dangerous reduces to one thing: both happen inside a process called the apply worker.
The apply worker is the background process running constantly inside the receiving database. It takes in reports from the sender saying "this row was added" or "this row was deleted" and writes the same changes into its own database. In pglogical's design, this background process ran with privileges equivalent to a PostgreSQL superuser, the account holding the highest privilege in the database. The single sentence in the CVE-2026-50737 description, that "because the apply worker runs at a privilege level equivalent to a PostgreSQL superuser in default installations, any function invoked by such a default expression also runs at that privilege," is the whole story here.
Restated as an everyday scene: the clerk who signs for incoming parcels happens to be carrying the master key to every room in the building. If a parcel contains a note saying "after you open this box, please also unlock the vault," the clerk holds the master key and can genuinely do it. There was no mechanism to doubt the contents of the parcel, and no mechanism to reduce the clerk's authority, so a malicious sender alone was enough to reach the vault.
This shape is not new to pglogical. In 2021, CVE-2021-3515 allowed OS commands to run as the postgres user through pglogical.create_subscription() by crafting a database name. That was fixed in 2.3.4. Five years apart, only the place where privilege lands is different; the pattern is the same.
What each of the four contains
CVE-2026-50736: Commands sent down the replication queue execute as superuser
pglogical has a mechanism called the queue. Separately from ordinary data changes such as inserting or deleting rows, it carries "commands that are not data," such as table restructuring (DDL), from the publisher to the subscriber. According to the NVD entry, the payload of a message placed on this queue is executed on the subscriber at the privilege level of the apply worker, which in default installations is equivalent to a superuser.
As a result, anyone able to act as the publisher only has to place a crafted message on the queue to run arbitrary SQL as superuser on the subscriber. NVD describes this as "escalating from a role permitted to use pglogical to full superuser and breaking the isolation between tenants in shared deployments." The CVSS 4.0 score from EDB is 9.0 (CRITICAL) with the vector CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H. The assigned class is CWE-89 (SQL injection), but the real problem is not a mistake in assembling a string; it is that the execution privilege is too high. CWE-250 (execution with unnecessary privileges), the class assigned to CVE-2026-50737, appears closer to the substance.
CVE-2026-50737: Default expressions run as superuser when a row arrives with missing columns
This one does not go through the queue. When the row data arriving from the publisher does not include some of the columns the subscriber's table has, pglogical evaluates that column's DEFAULT expression on the subscriber to fill it in. A PostgreSQL default can be a function call rather than a fixed value, so if a function has been planted there, applying a single row is enough to run it.
The process running that function is, again, the apply worker. The NVD entry states plainly that this is "a second, independent path to the same superuser escalation tracked under CVE-2026-50736." The CVSS 4.0 score is 9.0 (CRITICAL), identical to CVE-2026-50736, with the same vector. Having two entry points matters in practice: closing only one of them can be worked around. That is why the fix does not patch the queue and the default expression separately, but instead makes it possible to lower the privilege itself.
CVE-2026-50738: Use-after-free crashes the workers
pglogical's worker signaling code contains a use-after-free, a bug where memory that has already been released is referenced again. According to the NVD entry, the condition is reachable during entirely ordinary events such as workers starting, stopping and restarting, including by a low-privileged user who can shift the timing through permitted pglogical operations.
The upstream fix commit states the cause clearly: on transaction abort, the list of workers to signal (signal_workers) was not reset to empty even though its contents had already been freed. In the typical case the replication workers simply crash, so the impact is availability, meaning replication stops. NVD adds, however, that "in the worst case a use-after-free in a PostgreSQL backend can be leveraged as a remote code execution primitive at the privilege of that backend." EDB's CVSS 4.0 score of 7.7 (HIGH) reflects that worst case. What you will actually see first is replication stopping for no apparent reason.
CVE-2026-50735: Received data is copied without validating its length
This is the only one of the four that is not a privilege escalation. When the apply worker read replication protocol messages, it copied certain fields without sufficiently validating their length. That let it read past the end of the allocated memory region, disclosing the contents of adjacent process memory or crashing the worker.
The upstream fix commit lays out two problems side by side. First, the function that reads the message returns only a pointer into the buffer without copying, so the text representation was passed to the type input function without a terminating zero byte and kept reading past the attribute into adjacent heap memory. Second, the length preceding the internal representation was not checked against the receiver's own column definition, so passing a variable-length header claiming more data than was actually sent makes the tuple-handling code read beyond the attribute. The 2.4.8 changelog records this as sanitizing tuple data received from the upstream node, closing it with copying reads, length checks for fixed-length and variable-length types, and rejection of external datums.
One premise in the NVD description is telling: it says the publisher can be "a non-PostgreSQL endpoint that speaks the pglogical replication protocol." In other words, there is no need to stand up a real PostgreSQL instance; a fake publisher that merely speaks the protocol is enough to serve as the entry point. The CVSS 4.0 score is 6.1 (MEDIUM).
Which version do you have? A quick reference
Start by checking whether it is installed and at what version. Connect to the database and run the following. If nothing comes back, pglogical is not installed in that database.
SELECT extname, extversion FROM pg_extension WHERE extname = 'pglogical';
The problem is that even if you confirm you are affected, 2.4.8 has not yet arrived through most distribution channels. The table below reflects each distributor as checked at 04:30 UTC on July 29, 2026.
| Channel | Version shipped | Status |
|---|---|---|
| GitHub source (tag REL2_4_8) | 2.4.8 | Fixed |
| Debian unstable (sid) | 2.4.8-1 | Fixed |
| Debian testing (forky) | 2.4.7-1 | Affected |
| Debian 13 trixie (stable) | 2.4.5-1 | Affected |
| Debian 12 bookworm | 2.4.2-3 | Affected |
| Debian 11 bullseye | 2.3.3-3+deb11u1 | Affected |
| Ubuntu 24.04 LTS (noble) | 2.4.4-1 | Affected |
| Ubuntu 22.04 LTS (jammy) | 2.4.1-1 | Affected |
| PGDG apt (bookworm / trixie / jammy / noble) | 2.4.7-1 | Affected |
| PGDG yum (RHEL 9 / PostgreSQL 17) | 2.4.6-4 | Affected |
The last two rows carry the most operational weight. Most people install pglogical from the official PostgreSQL community repository (PGDG) as a package such as postgresql-17-pglogical. The newest version in that repository is still 2.4.7, so running apt upgrade or dnf update will not bring in the fix. Debian's security tracker has no entry for these four CVEs yet either, although the same page does list CVE-2021-3515 from 2021. For now the options are to build 2.4.8 from source, or to hold the line with the mitigations described below until packages are refreshed.
Upgrading to 2.4.8 does not lower the default privilege
Of everything in 2.4.8, this is the part most often read the wrong way. The 2.4.8 changelog lists the fix for CVE-2026-50736 and CVE-2026-50737 as "Add subscription_owner parameter to subscriptions." In other words, the hole was not plugged; a dial for lowering the privilege was added.
The upstream fix commit spells out the conclusion in its own message: "If this parameter is specified, the subscriptions are run with the permissions of this role. If you don't specify it, it runs as superuser." The official documentation added in the same commit states that "Default is empty, which tells PGLogical to run as superuser." A plain 2.4.8 install is, in privilege terms, the same as 2.4.7.
To lower the privilege you set pglogical.subscription_owner to a dedicated role and grant that role the privileges it needs by hand. The procedure the documentation lays out is not straightforward. SELECT, INSERT, UPDATE and DELETE on the target tables are not granted by synchronize_structure, so the initial synchronization succeeds and then the first change afterwards fails with a permission error. Access to pglogical's own catalogs (the pglogical schema) is required separately; without it the manager worker exits as soon as it starts and no subscription is ever launched. ALL TABLES only covers tables existing at the moment the command runs, so the grants must be repeated after an extension upgrade adds catalogs.
On top of that, replicated DDL and TRUNCATE are not applied directly. They are queued and replayed after a SET ROLE to the role that executed them on the provider, so the specified role must be a member of every role that runs DDL on the publisher. The documentation attaches a candid warning here: "Replicating DDL executed by a superuser thus leaves little of the isolation this parameter is meant to provide." If you keep the common operational habit of doing migration work under an administrative account, turning the dial has only limited effect.
The same commit also rewrote the heading in the documentation's limitations section from "Superuser is required" to "Superuser is required for administration." The new text separates the two: administrative operations (the functions that create nodes and subscriptions) need a superuser, but applying changes on the subscriber does not. That is an official correction to the design premise, and it goes further than the response to CVE-2021-3515 five years ago.
How narrow are the preconditions?
To avoid overstating this, let us cut the conditions precisely. This is not an internet-facing attack. The premise common to all four is that the attacker must be able to direct a subscription at an endpoint under their control. NVD continues: "In default installations this requires privileges normally reserved for a superuser, so the issue is most relevant to managed deployments where the ability to create subscriptions has been delegated to non-superuser roles."
There is a discrepancy here between the numbers and the prose. The CVSS 4.0 vector supplied by EDB says PR:L, meaning low privileges are required. The description says superuser-equivalent privileges are required in a default configuration. The two look contradictory, but they assume different environments. In a self-contained default configuration, anyone who can reach this already holds the highest privilege, so there is nothing to escalate to and the 9.0 figure diverges from the real threat level. In a managed or multi-tenant deployment where subscription creation has been delegated to ordinary roles, PR:L is correct and the 9.0 lands as written. The same CVE splits, by configuration, into "effectively harmless" and "total collapse of tenant isolation."
That asymmetry gives you an axis for reviewing your own setup. If any of the following applies, it is worth raising the priority. You replicate across organizations or departments. You receive from a database run by an affiliated company or a business partner. You offer replication to multiple customers. You have delegated the right to create subscriptions to non-superusers. If none apply and both publisher and subscriber are closed within your own team, waiting for packages to refresh and upgrading during normal maintenance is a defensible call.
Does moving to PostgreSQL's built-in logical replication solve it?
What pglogical does overlaps with the logical replication built into PostgreSQL 10 and later, which invites the idea of leaning on the built-in feature instead. Reading the primary sources, it is not a simple swap.
On privilege design, the built-in feature was put together later and more carefully. According to the PostgreSQL documentation, the apply process runs at session level with the privileges of the subscription owner and switches roles to the table owner when writing to each table. Creating a subscription requires the privileges of the pg_create_subscription role plus CREATE on the database, not superuser. That is a different starting point from pglogical, which runs as superuser by default.
The built-in feature has a comparable trap, though. On run_as_owner = true, the same document warns that "any user who owns a table into which replication is happening can execute arbitrary code with the privileges of the subscription owner. For example, they could do this by simply attaching a trigger to one of the tables which they own," and that "this option should be avoided unless user security within the database is of no concern." One setting puts you back in the same shape as pglogical.
Beyond that, the built-in logical replication has produced its own vulnerabilities in 2026: CVE-2026-6476 (SQL injection via subscription name in pg_createsubscriber, CVSS 7.2, fixed in 18.4 and 17.10) and CVE-2026-6638 (SQL injection via table name in REFRESH PUBLICATION, CVSS 3.7, fixed in 18.4, 17.10 and 16.14). The destination is not untouched.
There are functional gaps too. EDB's documentation lists pglogical's use cases as upgrades between major versions, full database replication, selective replication of sets of tables using replication sets, row-level filtering on either the publisher or the subscriber, and gathering or merging data from multiple upstream servers. The last of those, along with fine-grained row filters, does not map one-to-one onto the built-in feature. What can be said right now is only this: moving to the built-in feature improves the starting point for privilege design, whether the same capabilities are available depends on your configuration, and the migration itself is not a small piece of work. If you are weighing a move, take measurements in your own environment first, in the manner of our measured look at upgrading to PostgreSQL 18.
Was it installed for an upgrade and never removed?
Even if you do not remember deliberately installing pglogical, it may be there. The GitHub repository description sells the extension on "much faster replication than Slony, Bucardo or Londiste, as well as cross-version upgrades." When raising a PostgreSQL major version, a widely used procedure is to stand up old and new servers side by side, let pglogical catch the new one up, and then cut over, all to keep downtime short.
In that use, pglogical is a migration tool whose job ends at cutover. But DROP EXTENSION pglogical and removing it from shared_preload_libraries tend to sit at the bottom of the cutover-day checklist, and "it works, so leave it alone" keeps them there. An extension installed for an upgrade years ago may still be resident today, still carrying a worker with superuser-equivalent privilege. These four issues land squarely on that resident part.
Checking is easy. In addition to the pg_extension query above, running \dx in psql lists the installed extensions. If you are not using it, removing it is the most reliable fix, not upgrading it. This is also a good moment to ask, for every other extension, whether the reason it was installed still holds. Database extensions often sit outside OS package management, which makes them a layer that routine vulnerability scanning misses. Our approach to inventorying dependencies is collected in the OSS supply chain scanner.
Reading the numbers, and what is not settled yet
As of July 29, 2026, when this article was written, the state of the various indicators is as follows. This is laid out so that an absent number is not read as "safe."
| Indicator | State | How to read it |
|---|---|---|
| NVD CVSS | Not assigned (status: Received) | Awaiting NVD's own analysis. Displayed values come from EDB |
| EPSS | No score | Too soon after publication. Expected within days |
| CISA KEV | Not listed | No confirmed exploitation in the wild |
| CISA SSVC decision | Exploitation: none Automatable: no | Not the type sprayed by mass scanning |
| JVN / JVNDB (Japan) | No entry | No domestic advisory issued yet |
| Public PoC | None found | Fix commits are public and the method is readable from them |
A note on CVSS. The NVD pages do display CVSS 4.0 values, but they are marked "Secondary," meaning they were supplied by EDB as the assigning authority. NVD's own Primary assessment has not been entered and the CVE status remains Received, so the figures may move once NVD analyzes them. None of the four appear in the CISA KEV catalog (we track KEV listings in a dashboard of our own). That said, the SSVC decision from CISA's Vulnrichment program rates the technical impact of CVE-2026-50736, 50737 and 50738 as "total." The reading is: no observed exploitation, but total impact if it is reached.
EPSS, the estimated probability of exploitation within the next 30 days, had no record for any of the four in FIRST's API. Less than 24 hours have passed since publication, so they are not in scope for scoring yet.
✓ Confirmed facts
- ✓All four affect pglogical 2 below 2.4.8 and are fixed in 2.4.8 (NVD / the 2.4.8 release)
- ✓2.4.8 shipped at 18:10 UTC on July 28, 2026; the CVEs were registered in NVD roughly an hour later
- ✓The response to CVE-2026-50736 and CVE-2026-50737 is a new parameter,
pglogical.subscription_owner, which is not enabled by default (fix commit) - ✓Mehmet Ince (@mdisec) is credited as finder on all four CVE records
- ✓As of 04:30 UTC on July 29, 2026, the newest version in the official PostgreSQL community repositories is 2.4.7 for apt and 2.4.6 for yum
? Not confirmable at publication
- ?The individual EDB advisory pages listed as references in the CVE records (four URLs of the form
enterprisedb.com/docs/security/advisories/cve202650736/) all returned 404 when checked, and they do not appear in the advisory index either - ?EDB's pglogical 2 release notes have no entry for 2.4.8 yet
- ?Neither the OSV vulnerability database nor Debian's security tracker has registered these four yet
- ?The reporter's own technical write-up has not appeared on his disclosed CVE list
- ?No posts on X from the vendor, the reporter or well-known engineers referring to this disclosure could be found at the time of writing
Nothing in JVN, and nothing in Japanese
Searching JVNDB, the vulnerability database run by Japan's IPA and JPCERT/CC, for "pglogical" returns "no matching vulnerability information." Queries by CVE number find no entries for the four either. Neither JPCERT/CC's alerts nor IPA's important security notices cover them. A full-text search of Hatena Bookmark found zero Japanese blog or technical articles.
In other words, more than half a day after publication there is still no consolidated Japanese-language information on these four. Not many organizations in Japan run pglogical, but for those that do, two CVSS 9.0 issues land directly. Waiting for a JVN entry means the only decision material in the meantime is English primary sources.
The small size of the affected population deserves to be stated plainly. pglogical is not something every PostgreSQL user installs, and the GitHub repository has 1,231 stars as of this check. Public case studies of pglogical in production in Japan are limited. Even so, the shape holds: few organizations are affected, but in those that are, the highest privilege on the receiving database is directly at risk.
Upgrade to 2.4.8, then lower the privilege
Start with an inventory. Check pg_extension across every database in your PostgreSQL estate and record whether pglogical is present and at what version. Anything below 2.4.8 is affected. If it is present but unused, dropping the extension and removing it from shared_preload_libraries is the shortest and most reliable route.
If you are using it, let the configuration set the priority. If the publisher and subscriber have different administrators, if replication crosses organizations or customers, or if the right to create subscriptions has been handed to non-superusers, building 2.4.8 from source without waiting for packages is the reasonable call. Set pglogical.subscription_owner at the same time to lower the privilege. Because the setting requires the grants described above, run through initial synchronization and the first subsequent change in a test environment before going to production.
If you cannot move to 2.4.8 immediately, think about mitigation in terms of removing the preconditions. Restrict the ability to create subscriptions back to superusers only. Limit which publishers can be reached for replication connections through pg_hba.conf and at the network layer. Verify that the replication peer host is what you expect by inspecting the connection strings in pglogical.subscription. Each of the three breaks the premise that an attacker can point a subscription at an endpoint under their control. Because CVE-2026-50738 shows up as workers stopping for no clear reason, environments that do not yet monitor replication lag and worker restarts should add them now; it pays off later.
One generalizable point to close on. A system that receives data cannot defend itself with mechanisms that doubt the incoming content alone; it also needs a mechanism to lower the privilege of the receiving process. pglogical fixed the former, validating received data, in CVE-2026-50735, and only now provides the latter, privilege separation, as its response to CVE-2026-50736 and CVE-2026-50737. The same question applies to every resident process that handles input from outside, not just replication. Writing down what privilege each of those processes runs with, in your own environment, is worth the hour.
References
- â–¸ NVD - CVE-2026-50735 (July 28, 2026)
- â–¸ NVD - CVE-2026-50736 (July 28, 2026)
- â–¸ NVD - CVE-2026-50737 (July 28, 2026)
- â–¸ NVD - CVE-2026-50738 (July 28, 2026)
- â–¸ pglogical 2.4.8 release (GitHub) (July 28, 2026)
- â–¸ Add a subscription_owner parameter to subscriptions (fix commit)
- â–¸ pglogical official documentation (docs/README.md)
- â–¸ EDB Docs - pglogical 2
- â–¸ EDB - Security Advisories index
- â–¸ PostgreSQL documentation - Logical Replication Security
- â–¸ PostgreSQL - CVE-2026-6476
- â–¸ Debian Security Tracker - pglogical
- â–¸ NVD - CVE-2021-3515 (the 2021 pglogical issue)
- â–¸ Mehmet Ince - Disclosed CVEs
- â–¸ CISA - Known Exploited Vulnerabilities Catalog
- â–¸ FIRST - EPSS

Makoto Horikawa
Backend Engineer / AWS / Django