From 041f37c0980eec91edb6924726d3806d37426e25 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 19 Feb 2026 12:00:25 -0500
Subject: [PATCH v2 1/2] Be more wary of false matches in initdb's
 replace_token().

Do not replace the target string unless the occurrence is surrounded
by whitespace or line start/end.  This avoids potential false match
to a substring of a field.  While we've not had trouble with that
up to now, the next patch creates hazards of false matches to
POSTGRES within an ACL field.

There is one call site that needs adjustment, as it was presuming
it could write "::1" and have that match "::1/128".  For all the
others, this restriction is okay and strictly safer.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/183292bb-4891-4c96-a3ca-e78b5e0e1358@dunslane.net
---
 src/bin/initdb/initdb.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 7c49dd433a7..e9e1014bce9 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -461,7 +461,8 @@ add_stringlist_item(_stringlist **listhead, const char *str)
 
 /*
  * Modify the array of lines, replacing "token" by "replacement"
- * the first time it occurs on each line.
+ * the first time it occurs on each line.  To prevent false matches, the
+ * occurrence of "token" must be surrounded by whitespace or line start/end.
  *
  * The array must be a malloc'd array of individually malloc'd strings.
  * We free any discarded strings.
@@ -483,6 +484,7 @@ replace_token(char **lines, const char *token, const char *replacement)
 	for (int i = 0; lines[i]; i++)
 	{
 		char	   *where;
+		char	   *endwhere;
 		char	   *newline;
 		int			pre;
 
@@ -490,6 +492,17 @@ replace_token(char **lines, const char *token, const char *replacement)
 		if ((where = strstr(lines[i], token)) == NULL)
 			continue;
 
+		/*
+		 * Reject false match.  Note a blind spot: we don't check for a valid
+		 * match following a false match.  That case can't occur at present,
+		 * so not worth complicating this code for it.
+		 */
+		if (!(where == lines[i] || isspace((unsigned char) where[-1])))
+			continue;
+		endwhere = where + strlen(token);
+		if (!(*endwhere == '\0' || isspace((unsigned char) *endwhere)))
+			continue;
+
 		/* if we get here a change is needed - set up new line */
 
 		newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);
@@ -1496,11 +1509,11 @@ setup_config(void)
 			getaddrinfo("::1", NULL, &hints, &gai_result) != 0)
 		{
 			conflines = replace_token(conflines,
-									  "host    all             all             ::1",
-									  "#host    all             all             ::1");
+									  "host    all             all             ::1/128",
+									  "#host    all             all             ::1/128");
 			conflines = replace_token(conflines,
-									  "host    replication     all             ::1",
-									  "#host    replication     all             ::1");
+									  "host    replication     all             ::1/128",
+									  "#host    replication     all             ::1/128");
 		}
 	}
 
-- 
2.43.7

