highAug 24, 2026

postgres-protocol: Unbounded SCRAM Iteration Count CPU Exhaustion DoS

Rohit Hatagale
AI Security Researcher, SecureLayer7

A malicious or man-in-the-middle PostgreSQL server can send an arbitrarily large SCRAM-SHA-256 iteration count during login, forcing the Rust client to spin the CPU for minutes per connection and…

Packagepostgres-protocol
Ecosystemrust
Affected>= 0.3.0, < 0.6.12
Fixed in0.6.12
postgres-protocol: Unbounded SCRAM Iteration Count CPU Exhaustion DoS

The problem

The postgres-protocol crate parses the SCRAM-SHA-256 server-first-message during authentication and passes the server-supplied i= (iteration count) field directly into PBKDF2 with no upper bound.

An attacker who controls the server, or who sits between the client and a real server (MITM), can set i= to a value like 2147483647. The client dutifully runs that many PBKDF2-HMAC-SHA-256 rounds inline on a tokio worker thread, blocking it for minutes. With enough concurrent connections, the entire async runtime stalls.

Applications connecting only to a trusted, internal server are not at risk; the danger is real for any client that connects to user-supplied or untrusted server addresses.

Proof of concept

A working proof-of-concept for this issue in postgres-protocol, with the exact payload below.

text
-- Malicious server-first-message sent by attacker-controlled server
-- during SCRAM-SHA-256 handshake (RFC 5802 §7):
r=rOprNGfwEbeRWgbNEkqO<server-nonce>,s=W22ZaJ0SNY7soEsUEjb6tQ==,i=2147483647

SCRAM-SHA-256 (RFC 5802) requires the client to perform PBKDF2(password, salt, i) where i comes directly from the server message. Before the fix, postgres-protocol read the i= field as a plain integer and called the PBKDF2 routine with it unchanged, so the cost was fully server-controlled.

The patch at commit d40097a36a85068ea50a3afbf0ce154ba439e7f0 adds a hard upper-bound check: if the parsed iteration count exceeds the defined maximum, authentication is immediately aborted with an error rather than starting the PBKDF2 loop. This is CWE-770 (Allocation of Resources Without Limits or Throttling), where the scarce resource is CPU time rather than memory.

A comparable fix in the PostgreSQL JDBC driver caps the count at 100,000 before computation begins, confirming the class of fix used across the ecosystem.

The fix

Upgrade postgres-protocol to **0.6.12** or later. The fix is in commit d40097a36a85068ea50a3afbf0ce154ba439e7f0 in the rust-postgres/rust-postgres repository. If an immediate upgrade is not possible, restrict the crate to connections against known-trusted servers only, and terminate any connection whose SCRAM handshake takes longer than expected.

Reporter not attributed.

References: [1][2][3][4]

Related research