CVE-2026-54291: PostgreSQL JDBC Driver Silent SCRAM Channel-Binding Downgrade
A network attacker who can intercept TLS traffic can silently strip SCRAM channel-binding protection from a PostgreSQL JDBC connection that explicitly requires it, by presenting a server certificate…
The problem
pgJDBC 42.7.4 through 42.7.11 does not enforce channelBinding=require after SCRAM mechanism negotiation. ScramAuthenticator checks only that the server advertised a -PLUS mechanism, but never verifies the mechanism that was actually selected, and never rejects an empty channel-binding value.
The bundled scram-client 3.1/3.2 compounds the problem: when the server certificate uses Ed25519, Ed448, or a post-quantum algorithm, TlsServerEndpoint cannot derive the tls-server-end-point hash, swallows the NoSuchAlgorithmException, and returns an empty byte array instead of failing.
The two gaps together let a MITM silently downgrade the session from SCRAM-SHA-256-PLUS to plain SCRAM-SHA-256 with no client-side error.
Proof of concept
A working proof-of-concept for CVE-2026-54291 in org.postgresql:postgresql, with the exact payload below.
# Attacker-controlled PostgreSQL server presents an Ed25519 TLS certificate.
# The vulnerable JDBC client (42.7.4-42.7.11) silently accepts plain SCRAM-SHA-256
# even though it explicitly requested channelBinding=require.
# 1. Generate an Ed25519 server certificate (no tls-server-end-point hash exists for this algorithm)
openssl genpkey -algorithm Ed25519 -out server.key
openssl req -new -x509 -key server.key -out server.crt -days 365 \
-subj "/CN=db.example.com"
# 2. Configure PostgreSQL to use this certificate (postgresql.conf):
# ssl_cert_file = 'server.crt'
# ssl_key_file = 'server.key'
# 3. Victim JDBC client connects with what it believes is a channel-binding-enforced session:
# jdbc:postgresql://db.example.com:5432/mydb?channelBinding=require&ssl=true
#
# scram-client returns empty byte[] for the binding hash -> ScramAuthenticator
# does not detect this and does not check that the negotiated mechanism ends in -PLUS.
# Authentication completes over plain SCRAM-SHA-256; MITM wins.Two missing checks in ScramAuthenticator are the root cause (CWE-636, CWE-757). First, after scram-client returns the channel-binding value, the driver never tests whether the byte array is empty and does not abort the handshake. Second, after SCRAM mechanism negotiation completes, the driver never asserts that the selected mechanism name ends in -PLUS when channelBinding=require is configured.
The patch (commit 77df98e) adds both guards directly in pgJDBC's own code, independent of the scram-client version: it fails the connection immediately when the extracted binding data is empty (naming the unsupported certificate algorithm in the error), and it rejects the connection post-negotiation if the chosen mechanism is not a -PLUS variant. scram-client 3.3 separately fixes the library side by propagating the exception instead of swallowing it.
The fix
Upgrade to org.postgresql:postgresql 42.7.12 or later. No configuration workaround exists for the affected releases. As an interim network-layer mitigation only, set sslmode=verify-full with a truststore containing only your server's CA so that a MITM cannot substitute a certificate.
Connections relying solely on channelBinding=require for MITM protection must upgrade.
Reported by KEIJOT.
Related research
- highCVE-2026-53712CVE-2026-53712: scram-client SCRAM Channel-Binding Silent Authentication Downgrade
- highCVE-2026-10050CVE-2026-10050: Eclipse Jetty Digest Authentication Bypass via ISO-8859-1 Encoding Collision
- high · 7.5CVE-2024-7708CVE-2024-7708: Eclipse Jetty jetty-server Buffer Leak DoS via 100-Continue Requests
- highCVE-2026-56745CVE-2026-56745: netty-codec-http SpdyHttpDecoder ByteBuf Reference Leak