highCVE-2026-53712Jul 1, 2026

CVE-2026-53712: scram-client SCRAM Channel-Binding Silent Authentication Downgrade

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

A flaw in the OnGres SCRAM Java library lets a TLS man-in-the-middle silently strip channel binding from a SCRAM-SHA-256-PLUS login, defeating the only protection that channelBinding=require is suppos

Packagecom.ongres.scram:scram-client
Ecosystemmaven
Affected<= 3.2
Fixed in3.3

The problem

In scram-client 3.1 and 3.2, TlsServerEndpoint.getChannelBindingData() catches NoSuchAlgorithmException when the server presents a certificate signed with an algorithm that has no traditional WITH naming structure (Ed25519, Ed448, post-quantum). It swallows the exception and returns an empty byte array.

The ScramClient builder sees a non-null but empty binding byte array and interprets it as an environmental absence of channel binding support. It silently falls back to plain SCRAM-SHA-256, bypassing channel binding entirely. Only connections with an explicit channelBinding=require policy are exposed; the default prefer/allow policies treat the fallback as normal.

Proof of concept

A working proof-of-concept for CVE-2026-53712 in com.ongres.scram:scram-client, with the exact payload below.

java
// Attacker positions themselves as a TLS MITM and presents a server certificate
// using an algorithm with no tls-server-end-point hash (e.g., Ed25519).
// The vulnerable library path:

// 1. Client calls the deprecated API:
byte[] cbData = TlsServerEndpoint.getChannelBindingData(ed25519Cert);
// => NoSuchAlgorithmException is swallowed; cbData == new byte[0]

// 2. Builder treats empty array as "no binding data available":
ScramClient client = ScramClient.builder()
    .advertisedMechanisms(List.of("SCRAM-SHA-256", "SCRAM-SHA-256-PLUS"))
    .username("postgres")
    .password("secret".toCharArray())
    // cbData is empty: builder falls through to non-PLUS mechanism
    .channelBinding(TlsServerEndpoint.TLS_SERVER_END_POINT, cbData)
    .build();
// => negotiated mechanism is SCRAM-SHA-256 (no channel binding)
// => channelBinding=require policy is silently violated

The root cause is a CWE-636 / CWE-757 compound: the code fails open instead of failing hard. getChannelBindingData() was documented as deprecated precisely because it swallows the algorithm exception; the builder had no way to distinguish an empty hash from a missing one.

The patch in 3.3 replaces getChannelBindingData() with getChannelBindingHash(), which propagates NoSuchAlgorithmException up the stack instead of returning an empty byte array. A new ChannelBindingPolicy enum (DISABLE, ALLOW, REQUIRE) is introduced so the builder can enforce hard failure on negotiation rather than relying on implicit parameter presence.

RSASSA-PSS certificate support is also added so modern algorithm families no longer produce the exception at all.

The fix

Upgrade com.ongres.scram:scram-client to 3.3. Stop calling the deprecated TlsServerEndpoint.getChannelBindingData(); switch to TlsServerEndpoint.getChannelBindingHash(), which throws on unsupported algorithms. If you build ScramClient directly, add .channelBindingPolicy(ChannelBindingPolicy.REQUIRE) to make downgrade impossible at the library level rather than relying on the driver layer. pgJDBC users should also upgrade to 42.7.12 or later, which fixes the companion driver-side enforcement gap.

Reporter not attributed.

References: [1][2]

Related research