From b2e1dfffd1de50802bbe75f5ea3e5dc74047f736 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Tue, 28 Jul 2026 17:46:47 +0530
Subject: [PATCH v1] Check foreign server permissions for ALTER SUBSCRIPTION
 ... ADD/DROP/SET/REFRESH PUBLICATION

When a subscription is created using a foreign server, ALTER
SUBSCRIPTION ... REFRESH PUBLICATION, ADD PUBLICATION, DROP
PUBLICATION, and SET PUBLICATION may connect to the publisher to
fetch the updated relation list.

However, AlterSubscription() calls GetSubscription() with
conninfo_aclcheck set to false, which skips the ACL check on the
associated foreign server. As a result, these commands can
successfully connect to the publisher even when the user does not
have permission to access the server.

Fix this by enabling conninfo_aclcheck for these ALTER SUBSCRIPTION
operations so that access permissions on the foreign server are
validated before establishing the connection.
---
 src/backend/commands/subscriptioncmds.c    | 17 ++++++++++++++++-
 src/test/regress/expected/subscription.out |  7 +++++++
 src/test/regress/sql/subscription.sql      |  8 ++++++++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 013ac46db07..bf6e644be35 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -1618,6 +1618,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 	Datum		values[Natts_pg_subscription];
 	HeapTuple	tup;
 	Oid			subid;
+	bool		orig_conninfo_aclchk = false;
 	bool		orig_conninfo_needed = true;
 	bool		update_tuple = false;
 	bool		update_failover = false;
@@ -1728,6 +1729,19 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 		if (opts.specified_opts == SUBOPT_SLOT_NAME && !opts.slot_name)
 			orig_conninfo_needed = false;
 	}
+	else if (stmt->kind == ALTER_SUBSCRIPTION_REFRESH_PUBLICATION ||
+			 stmt->kind == ALTER_SUBSCRIPTION_ADD_PUBLICATION ||
+			 stmt->kind == ALTER_SUBSCRIPTION_DROP_PUBLICATION ||
+			 stmt->kind == ALTER_SUBSCRIPTION_SET_PUBLICATION)
+	{
+		/*
+		 * ALTER SUBSCRIPTION ... REFRESH PUBLICATION, ADD PUBLICATION, DROP
+		 * PUBLICATION, and SET PUBLICATION connect to the publisher to fetch
+		 * the updated publication information. Validate the permissions on
+		 * the original foreign server.
+		 */
+		orig_conninfo_aclchk = true;
+	}
 
 	/*
 	 * Skip ACL checks on the subscription's foreign server, if any. If
@@ -1736,7 +1750,8 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 	 * there's no need to do an additional ACL check here; that will be done
 	 * by the subscription worker.
 	 */
-	sub = GetSubscription(subid, false, orig_conninfo_needed, false);
+	sub = GetSubscription(subid, false, orig_conninfo_needed,
+						  orig_conninfo_aclchk);
 
 	retain_dead_tuples = sub->retaindeadtuples;
 	origin = sub->origin;
diff --git a/src/test/regress/expected/subscription.out b/src/test/regress/expected/subscription.out
index 1bb785f4f9f..4e8a67392ed 100644
--- a/src/test/regress/expected/subscription.out
+++ b/src/test/regress/expected/subscription.out
@@ -193,6 +193,13 @@ CREATE SUBSCRIPTION regress_testsub6 SERVER test_server
 WARNING:  subscription was created, but is not connected
 HINT:  To initiate replication, you must manually create the replication slot, enable the subscription, and alter the subscription to refresh publications.
 RESET SESSION AUTHORIZATION;
+REVOKE USAGE ON FOREIGN SERVER test_server FROM regress_subscription_user3;
+SET SESSION AUTHORIZATION regress_subscription_user3;
+-- fail, need USAGE privileges on the server
+ALTER SUBSCRIPTION regress_testsub6 REFRESH PUBLICATION;
+ERROR:  subscription owner "regress_subscription_user3" does not have permission on foreign server "test_server"
+RESET SESSION AUTHORIZATION;
+GRANT USAGE ON FOREIGN SERVER test_server TO regress_subscription_user3;
 GRANT USAGE ON FOREIGN SERVER test_server TO regress_subscription_user2;
 CREATE USER MAPPING FOR regress_subscription_user2 SERVER test_server OPTIONS(user 'foo');
 ALTER FOREIGN DATA WRAPPER test_fdw CONNECTION test_fdw_connection_no_password;
diff --git a/src/test/regress/sql/subscription.sql b/src/test/regress/sql/subscription.sql
index f19740fdfb8..aa0b3d722ff 100644
--- a/src/test/regress/sql/subscription.sql
+++ b/src/test/regress/sql/subscription.sql
@@ -140,6 +140,14 @@ CREATE SUBSCRIPTION regress_testsub6 SERVER test_server
   PUBLICATION testpub WITH (slot_name = 'dummy', connect = false);
 
 RESET SESSION AUTHORIZATION;
+REVOKE USAGE ON FOREIGN SERVER test_server FROM regress_subscription_user3;
+SET SESSION AUTHORIZATION regress_subscription_user3;
+
+-- fail, need USAGE privileges on the server
+ALTER SUBSCRIPTION regress_testsub6 REFRESH PUBLICATION;
+
+RESET SESSION AUTHORIZATION;
+GRANT USAGE ON FOREIGN SERVER test_server TO regress_subscription_user3;
 GRANT USAGE ON FOREIGN SERVER test_server TO regress_subscription_user2;
 CREATE USER MAPPING FOR regress_subscription_user2 SERVER test_server OPTIONS(user 'foo');
 ALTER FOREIGN DATA WRAPPER test_fdw CONNECTION test_fdw_connection_no_password;
-- 
2.34.1

