v3-0002-Avoid-exposing-raw-WAL-receiver-conninfo-during-t.patch

application/octet-stream

Filename: v3-0002-Avoid-exposing-raw-WAL-receiver-conninfo-during-t.patch
Type: application/octet-stream
Part: 1
Message: Re: Fix pg_stat_wal_receiver to show CONNECTING status
From 4dfab1d904ac6b86a7452d011e86379fba86623b Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <lic@highgo.com>
Date: Fri, 22 May 2026 09:46:16 +0800
Subject: [PATCH v3 2/2] Avoid exposing raw WAL receiver conninfo during
 timeline jumps

When reusing an existing WAL receiver after it has reached
WALRCV_WAITING, RequestXLogStreaming() copied PrimaryConnInfo into
WalRcv->conninfo before switching the state to WALRCV_RESTARTING.  At
that point ready_to_display could still be true, so pg_stat_wal_receiver
could expose the raw connection string, including sensitive fields.

WALRCV_RESTARTING does not establish a new connection.  The waiting WAL
receiver reuses its existing connection and only needs a new startpoint
and timeline, so there is no need to copy the raw connection string into
shared memory again.  Only copy conninfo when launching a new WAL receiver
from WALRCV_STOPPED.

Add coverage to the timeline-switch test to verify that the WAL receiver
process remains visible in pg_stat_wal_receiver across the jump, while a
raw password in primary_conninfo is not exposed.

Author: Chao Li <lic@highgo.com>
Reviewed-by:
Discussion: https://postgr.es/m/EF91FF76-1E2B-4F3B-9162-290B4DC517FF@gmail.com
---
 src/backend/replication/walreceiverfuncs.c |  9 ++++-----
 src/test/recovery/t/004_timeline_switch.pl | 16 ++++++++++++++--
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index a0ed853e2f6..279c6c8a7e1 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -281,11 +281,6 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
 	Assert(walrcv->walRcvState == WALRCV_STOPPED ||
 		   walrcv->walRcvState == WALRCV_WAITING);
 
-	if (conninfo != NULL)
-		strlcpy(walrcv->conninfo, conninfo, MAXCONNINFO);
-	else
-		walrcv->conninfo[0] = '\0';
-
 	/*
 	 * Use configured replication slot if present, and ignore the value of
 	 * create_temp_slot as the slot name should be persistent.  Otherwise, use
@@ -307,6 +302,10 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
 	{
 		launch = true;
 		walrcv->walRcvState = WALRCV_STARTING;
+		if (conninfo != NULL)
+			strlcpy(walrcv->conninfo, conninfo, MAXCONNINFO);
+		else
+			walrcv->conninfo[0] = '\0';
 	}
 	else
 		walrcv->walRcvState = WALRCV_RESTARTING;
diff --git a/src/test/recovery/t/004_timeline_switch.pl b/src/test/recovery/t/004_timeline_switch.pl
index 5afd2f44466..eb7cfa9f8e0 100644
--- a/src/test/recovery/t/004_timeline_switch.pl
+++ b/src/test/recovery/t/004_timeline_switch.pl
@@ -47,11 +47,15 @@ $node_standby_1->psql(
 	stdout => \$psql_out);
 is($psql_out, 't', "promotion of standby with pg_promote");
 
-# Switch standby 2 to replay from standby 1
+# Switch standby 2 to replay from standby 1.  During the timeline switch,
+# the WAL receiver process on standby 2 should not be stopped, and the
+# new primary connection string should not be visible
+# in pg_stat_wal_receiver.
+my $secret = 'dont_show_me';
 my $connstr_1 = $node_standby_1->connstr;
 $node_standby_2->append_conf(
 	'postgresql.conf', qq(
-primary_conninfo='$connstr_1'
+primary_conninfo='$connstr_1 password=$secret'
 ));
 
 # Rotate logfile before restarting, for the log checks done below.
@@ -93,6 +97,14 @@ my $wr_pid_after_switch = $node_standby_2->safe_psql('postgres',
 is($wr_pid_before_switch, $wr_pid_after_switch,
 	'WAL receiver PID matches across timeline jumps');
 
+my $raw_conninfo_count = $node_standby_2->safe_psql(
+	'postgres',
+	"SELECT count(*) FROM pg_stat_wal_receiver WHERE conninfo LIKE '%$secret%'");
+
+is(
+	$raw_conninfo_count, '0',
+	'raw primary_conninfo password is not visible after timeline jumps');
+
 # Ensure that a standby is able to follow a primary on a newer timeline
 # when WAL archiving is enabled.
 
-- 
2.50.1 (Apple Git-155)