## https://sploitus.com/exploit?id=7FC65BF6-915D-5B79-BD75-C1019BBA822F
# PostgreSQL CVE-2026-6471: logical decoding dlopen of an arbitrary library
PostgreSQL logical decoding lets a non-superuser role that holds the
`REPLICATION` privilege create a logical replication slot and choose the
output plugin. On affected versions there is no authorization check on that
choice, so the server `dlopen()`s whatever the plugin name points to. Naming
a library path runs that library's code inside the postgres backend, as the
operating system account that runs the server. That is arbitrary code
execution as the database server's OS user, which for a database holding the
application data is effectively server takeover.
Fixed in PostgreSQL 18.6, 17.11, 16.15, 15.19, and 14.24 by the
`output_plugin_libraries` allowlist (default `pgoutput, test_decoding`).
Anything not on that list now errors with `library "X" may not be used as an
output plugin` before any `dlopen`.
## What the PoC shows
Run the same steps against both builds and only the PostgreSQL version
changes. A low-privilege account (LOGIN + REPLICATION, not superuser) does
what a normal logical decoding subscriber does, then asks the server to load
an arbitrary library as the output plugin:
| step | vulnerable 16.14 | patched 16.15 |
| --- | --- | --- |
| recon (role is replication, not superuser) | passes | passes |
| baseline (logical slot with built-in pgoutput) | passes | passes |
| trigger (slot plugin = attacker library path) | server dlopen's it | rejected before load |
| verify (library marker file present) | present | absent |
## The files
- `cve-2026-6471-postgres-logical-decoding-dlopen.txt` is an Exploitmatic
solution (.txt): data plus asserts, no code. The runtime replays it against
the box. The solution delivers `pwn.so` at run time (base64 in the file),
drives the SQL as the low-privilege replication role, and asserts on the
marker the library writes.
- `pwn.c` is the payload library source and `pwn.so` its build: a single ELF
constructor that writes `/tmp/cve-2026-6471-pwned`. It runs only if the
server actually loads the library, i.e. only on a vulnerable build. Build
with `gcc -Os -shared -fPIC -o pwn.so pwn.c` on a Linux libc matching the
server image.
## Run it
Preconditions: you have docker access, and the target is an official
postgres image with `wal_level=logical` plus a `LOGIN REPLICATION` (not
superuser) role. See the replica Dockerfiles in the workspace lab for the
exact setup.
```
exploitmatic run cve-2026-6471-postgres-logical-decoding-dlopen.txt 127.0.0.1
```
Point at the patched box with a variable override, no file edit:
```
exploitmatic run cve-2026-6471-postgres-logical-decoding-dlopen.txt 127.0.0.1 \
--var ctr=pg-6471-fixed
```
`ctr` is the docker container, `pw` is the replication role's password.
## Verified
| target | result |
| --- | --- |
| postgres 16.14 (vulnerable), wal_level=logical | 4/4 verified, marker present |
| postgres 16.15 (patched), wal_level=logical | 3/4 not verified, marker absent |
## Scope
For authorized testing and research only, on systems you own or have
permission to test. This PoC demonstrates a post-authentication privilege
escalation: it requires an existing low-privilege database account with the
REPLICATION attribute, plus a way to place attacker-controlled code where
the postgres OS user can load it. It is not a remote unauthenticated
attack.
## References
- CVE-2026-6471 (PostgreSQL security advisory)
- Exploitmatic runtime: https://github.com/exploitmatic/exploitmatic