From b9f5d1ad535547ebb1469e788d467161f75af6f2 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Thu, 16 Jul 2026 15:01:31 +0200
Subject: [PATCH] Fix truncation rules for base64 encoding

Commit e1d917182 added support for base64url encoding, a base64 variant
intended to be safe for usage in URLs and filenames.  The padding rules
for base64url and base64 differ in that base64url require no extra '='
padding, but the commit unintentionally relaxed this requirement for
base64 as well.  Fix by making sure that the truncation logic check
for the encoding and add a test to make sure.

Backpatch down to v19 where base64url was introduced.

Author: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: ...
Discussion: https://postgr.es/m/...
Backpatch-through: 19
---
 src/backend/utils/adt/encode.c        | 4 ++--
 src/test/regress/expected/strings.out | 4 ++++
 src/test/regress/sql/strings.sql      | 3 +++
 3 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c
index 9ea3ddb49ec..b9d4f2811d7 100644
--- a/src/backend/utils/adt/encode.c
+++ b/src/backend/utils/adt/encode.c
@@ -583,12 +583,12 @@ pg_base64_decode_internal(const char *src, size_t len, char *dst, bool url)
 		}
 	}
 
-	if (pos == 2)
+	if (url && pos == 2)
 	{
 		buf <<= 12;
 		*p++ = (buf >> 16) & 0xFF;
 	}
-	else if (pos == 3)
+	else if (url && pos == 3)
 	{
 		buf <<= 6;
 		*p++ = (buf >> 16) & 0xFF;
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index a49b75fa1f9..313c5039465 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -2810,6 +2810,10 @@ SELECT decode('AQ', 'base64url');    -- \x01
  \x01
 (1 row)
 
+-- Make sure the same 1 byte input isn't accepted as base64
+SELECT decode('AQ', 'base64');    -- \x01
+ERROR:  invalid base64 end sequence
+HINT:  Input data is missing padding, is truncated, or is otherwise corrupted.
 -- 2 byte input
 SELECT encode('\x0102'::bytea, 'base64url');  -- AQI
  encode 
diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql
index 5ae0e7da31a..38946e8954d 100644
--- a/src/test/regress/sql/strings.sql
+++ b/src/test/regress/sql/strings.sql
@@ -909,6 +909,9 @@ SELECT decode('', 'base64url');  -- ''
 SELECT encode('\x01', 'base64url');  -- AQ
 SELECT decode('AQ', 'base64url');    -- \x01
 
+-- Make sure the same 1 byte input isn't accepted as base64
+SELECT decode('AQ', 'base64');    -- \x01
+
 -- 2 byte input
 SELECT encode('\x0102'::bytea, 'base64url');  -- AQI
 SELECT decode('AQI', 'base64url');            -- \x0102
-- 
2.39.3 (Apple Git-146)

