Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1x4dcr-007IBN-23 for pgsql-bugs@arkaria.postgresql.org; Thu, 10 Sep 2026 12:11:33 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1x4dcq-005U8E-27 for pgsql-bugs@arkaria.postgresql.org; Thu, 10 Sep 2026 12:11:32 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1x3a30-001t1s-2p for pgsql-bugs@lists.postgresql.org; Mon, 07 Sep 2026 14:10:10 +0000 Received: from mahout.postgresql.org ([2001:4800:3e1:1::227]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1x3a2v-00000003PvY-35tj for pgsql-bugs@lists.postgresql.org; Mon, 07 Sep 2026 14:10:10 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=postgresql.org; s=20171124; h=Message-ID:Date:Reply-To:Cc:From:To:Subject: Content-Transfer-Encoding:MIME-Version:Content-Type:Sender:Content-ID: Content-Description:In-Reply-To:References; bh=YZmXgrepKTrAm8ziu14rXptUe7nH/EeaIixwj16d4GU=; b=ocvq2OwjwuS3t+DEN2lONySRzI bDffaWWqAHKfwvwOX2/5OMPT/fGVW3aW8KRxtmqIzF8RvGOdoDQZzU+ttyGldA3OfdlpuC+adHGyk eXYGfK51rn4fRGaXM36F+G08JzvOJnyC0NZ9g2qkmpk1yGBoqAJn72v10G/hONUZFjZNZVSR82adl xiP7+WjCuCAfws6oXfziSrfYsCnoMELsVT2seYiUXIl2N2WH1bZazLtDBdlnYxJkU5cYC+hrBKHnG n8Um15t+Nz7aWu6AOizxyGXpPEWh537bCjj34m6wYHRF0+oNw0/LYbe+Na/fATv3/guvNznJQVpXr aAjK2rMQ==; Received: from wrigleys.postgresql.org ([2a02:16a8:dc51::60]) by mahout.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1x3a2u-00DTRU-1R for pgsql-bugs@lists.postgresql.org; Mon, 07 Sep 2026 14:10:04 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.98.2) (envelope-from ) id 1x3a2t-00000000fz9-0fzY for pgsql-bugs@lists.postgresql.org; Mon, 07 Sep 2026 14:10:03 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19671: IPv4 CIDR Prefix Integer Overflow Bypasses Validation in inet/cidr Casts To: pgsql-bugs@lists.postgresql.org From: PG Bug reporting form Cc: 1950233439@qq.com Reply-To: 1950233439@qq.com, pgsql-bugs@lists.postgresql.org Date: Mon, 07 Sep 2026 14:09:09 +0000 Message-ID: <19671-9b75c5d8b03fd33b@postgresql.org> X-Auto-Response-Suppress: All Auto-Submitted: auto-generated List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk The following bug has been logged on the website: Bug reference: 19671 Logged by: Tianyu Shi Email address: 1950233439@qq.com PostgreSQL version: 19beta3 Operating system: Ubuntu22.04 Description: =20 ### Summary In `src/backend/utils/adt/inet_net_pton.c`, both `inet_cidr_pton_ipv4()` (lines 177=E2=80=93188) and `inet_net_pton_ipv4()` (lines 296=E2=80=93308) = accumulate the CIDR prefix length digit-by-digit with no per-digit overflow guard, allowing a 32-bit signed `int bits` to wrap silently on inputs such as `4294967297` (2=C2=B3=C2=B2+1 =E2=86=92 1). The post-loop check `if (bits > 32) goto ems= gsize` then sees the wrapped value and passes it, causing any non-privileged SQL user to store `inet`/`cidr` values with silently corrupted prefix lengths. An attacker who can INSERT into a table with an `inet`/`cidr` column, or supply a cast literal, can produce entries whose stored masklen differs arbitrarily from what was written, potentially bypassing application-layer ACL logic built on PostgreSQL subnet-containment operators. ### PoC No superuser required; any user able to execute a `SELECT` or `INSERT` with an `inet`/`cidr` cast is sufficient. ```sql \set ON_ERROR_STOP off -- Test 1: inet cast =E2=80=94 4294967297 =3D 2^32+1 wraps to 1; should ERR= OR but does not SELECT masklen('1.2.3.4/4294967297'::inet) AS actual_masklen; -- Observed: 1 Expected: ERROR -- Test 2: cidr cast =E2=80=94 4294967296 =3D 2^32 wraps to 0; should ERROR= but does not SELECT masklen('0.0.0.0/4294967296'::cidr) AS actual_masklen; -- Observed: 0 Expected: ERROR -- Control: legitimate out-of-range /33 is correctly rejected SELECT masklen('1.2.3.4/33'::inet) AS should_error; -- Observed: ERROR: invalid input syntax for type inet: "1.2.3.4/33" -- Stored value demonstration SELECT host('1.2.3.4/4294967297'::inet) AS inet_host, masklen('1.2.3.4/4294967297'::inet) AS inet_masklen_actual, 1 AS inet_masklen_expected; -- Returns: 1.2.3.4 | 1 | 1 (value accepted and stored with wrong prefix) ``` ### Result - `'1.2.3.4/4294967297'::inet` =E2=80=94 expected `ERROR: invalid mask leng= th`; actual `masklen() =3D 1` (2=C2=B3=C2=B2+1 wraps to 1, bypass confirmed). - `'0.0.0.0/4294967296'::cidr` =E2=80=94 expected `ERROR: invalid mask leng= th`; actual `masklen() =3D 0` (2=C2=B3=C2=B2 wraps to 0, bypass confirmed). - `'1.2.3.4/33'::inet` =E2=80=94 correctly raises `ERROR: invalid input syn= tax for type inet: "1.2.3.4/33"` (normal in-range bound check works). The asymmetry demonstrates that only the integer-overflow path escapes validation: overflowing prefix literals are silently accepted and stored with a wrong (wrapped) prefix length, while a straightforward out-of-range value is rejected. Any application relying on `<<` / `<<=3D` subnet comparisons against stored `inet`/`cidr` values is exposed to logic bypass via entries whose effective mask is broader than intended.