Summary
Bind.Decode in pgproto3/bind.go contains an incomplete bounds check that allows a server-controlled negative parameter length (other than the null sentinel -1) to bypass validation and cause an immediate client-side panic.
Vulnerable Code
The parameter length is correctly read as a signed integer:
msgSize := int(int32(binary.BigEndian.Uint32(src[rp:])))
The null sentinel check (msgSize == -1) is correct. However, the bounds check that follows is:
if len(src[rp:]) < msgSize {
return &invalidMessageFormatErr{...}
}
len() always returns a non-negative value. When msgSize is any negative value other than -1, the comparison is always false and the guard is bypassed entirely. Execution reaches:
dst.Parameters[i] = src[rp : rp+msgSize]
A negative slice upper bound causes an immediate, unrecoverable runtime panic:
panic: runtime error: slice bounds out of range [:-13619142]
Root Cause
The identical guard is already present in DataRow.Decode in the same package but was not applied to Bind.Decode:
// DataRow.Decode — correct:
} else if valueLen < 0 {
return &invalidMessageFormatErr{messageType: "DataRow"}
}
Fix
Add a single additional condition to the existing bounds check:
- if len(src[rp:]) < msgSize {
+ if msgSize < 0 || len(src[rp:]) < msgSize {
return &invalidMessageFormatErr{messageType: "Bind"}
}
Impact
A malicious or compromised PostgreSQL server can crash any pgx/v5 client process by sending a Bind message with a parameter length field set to any negative value other than -1 (e.g. 0xFFFFEB7A → int32 = -5254). No authentication is required — only the ability to route the client to an attacker-controlled endpoint.
Reference
https://securityinfinity.com/research/pgx-v5-bind-decode-negative-parameter-length-bypass
Summary
Bind.Decodeinpgproto3/bind.gocontains an incomplete bounds check that allows a server-controlled negative parameter length (other than the null sentinel-1) to bypass validation and cause an immediate client-side panic.pgproto3/bind.goCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HVulnerable Code
The parameter length is correctly read as a signed integer:
The null sentinel check (
msgSize == -1) is correct. However, the bounds check that follows is:len()always returns a non-negative value. WhenmsgSizeis any negative value other than-1, the comparison is alwaysfalseand the guard is bypassed entirely. Execution reaches:A negative slice upper bound causes an immediate, unrecoverable runtime panic:
Root Cause
The identical guard is already present in
DataRow.Decodein the same package but was not applied toBind.Decode:Fix
Add a single additional condition to the existing bounds check:
Impact
A malicious or compromised PostgreSQL server can crash any pgx/v5 client process by sending a
Bindmessage with a parameter length field set to any negative value other than-1(e.g.0xFFFFEB7A→int32 = -5254). No authentication is required — only the ability to route the client to an attacker-controlled endpoint.Reference
https://securityinfinity.com/research/pgx-v5-bind-decode-negative-parameter-length-bypass