From 635d5db73676e3db751f81f2bba62afcde892642 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Thu, 12 Feb 2026 04:43:43 +0000 Subject: [PATCH] fix(sql): enforce minimum PBKDF2 iteration count in SCRAM-SHA-256 auth Reject SCRAM SASLContinue messages with PBKDF2 iteration counts below 4096 (the RFC 7677 recommended minimum). Without this check, a MITM attacker could modify the server's iteration count to 1, reducing PBKDF2 to a single HMAC iteration and making offline password brute-force ~4096x faster. Co-Authored-By: Claude --- src/sql/postgres/AnyPostgresError.zig | 2 ++ src/sql/postgres/SASL.zig | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/sql/postgres/AnyPostgresError.zig b/src/sql/postgres/AnyPostgresError.zig index 6e93fa39c4..07dc874e5f 100644 --- a/src/sql/postgres/AnyPostgresError.zig +++ b/src/sql/postgres/AnyPostgresError.zig @@ -20,6 +20,7 @@ pub const AnyPostgresError = error{ OutOfMemory, Overflow, PBKDFD2, + SASL_ITERATION_COUNT_TOO_LOW, SASL_SIGNATURE_MISMATCH, SASL_SIGNATURE_INVALID_BASE64, ShortRead, @@ -97,6 +98,7 @@ pub fn postgresErrorToJS(globalObject: *jsc.JSGlobalObject, message: ?[]const u8 error.NullsInArrayNotSupportedYet => "ERR_POSTGRES_NULLS_IN_ARRAY_NOT_SUPPORTED_YET", error.Overflow => "ERR_POSTGRES_OVERFLOW", error.PBKDFD2 => "ERR_POSTGRES_AUTHENTICATION_FAILED_PBKDF2", + error.SASL_ITERATION_COUNT_TOO_LOW => "ERR_POSTGRES_SASL_ITERATION_COUNT_TOO_LOW", error.SASL_SIGNATURE_MISMATCH => "ERR_POSTGRES_SASL_SIGNATURE_MISMATCH", error.SASL_SIGNATURE_INVALID_BASE64 => "ERR_POSTGRES_SASL_SIGNATURE_INVALID_BASE64", error.TLSNotAvailable => "ERR_POSTGRES_TLS_NOT_AVAILABLE", diff --git a/src/sql/postgres/SASL.zig b/src/sql/postgres/SASL.zig index 7ae2bbd0f1..dc0da61dd6 100644 --- a/src/sql/postgres/SASL.zig +++ b/src/sql/postgres/SASL.zig @@ -8,6 +8,13 @@ const server_signature_base64_len = bun.base64.encodeLenFromSize(server_signatur const salted_password_byte_len = 32; +/// Minimum PBKDF2 iteration count to prevent MITM downgrade attacks. +/// RFC 7677 recommends a minimum of 4096 iterations for SCRAM-SHA-256. +/// A MITM attacker could modify the SASLContinue message to set a low +/// iteration count (e.g., i=1), making offline password brute-force +/// significantly faster. +const min_iteration_count = 4096; + nonce_base64_bytes: [nonce_base64_len]u8 = .{0} ** nonce_base64_len, nonce_len: u8 = 0, @@ -35,6 +42,9 @@ fn hmac(password: []const u8, data: []const u8) ?[32]u8 { } pub fn computeSaltedPassword(this: *SASL, salt_bytes: []const u8, iteration_count: u32, connection: *PostgresSQLConnection) !void { + if (iteration_count < min_iteration_count) { + return error.SASL_ITERATION_COUNT_TOO_LOW; + } this.salted_password_created = true; if (Crypto.EVP.pbkdf2(&this.salted_password_bytes, connection.password, salt_bytes, iteration_count, .sha256) == null) { return error.PBKDFD2;