[PATCH] Add enable_copy_program GUC to control COPY PROGRAM

Ignat Remizov <ignat980@gmail.com>

From: Ignat Remizov <ignat980@gmail.com>
To:
Date: 2025-12-03T09:01:31Z
Lists: pgsql-hackers
Introduce a new postmaster-only GUC parameter enable_copy_program to
control the use of COPY ... PROGRAM. By default this parameter is set
to on, allowing the use of COPY ... PROGRAM and preserving existing
behavior. When set to off, attempts to use COPY ... PROGRAM are
rejected, even for superusers or roles with the pg_execute_server_program
privilege.

Key changes:
- Add enable_copy_program as a postmaster-only GUC parameter.
- Update COPY command logic to enforce the enable_copy_program setting.
- Update documentation to reflect the new parameter and its behavior.
- Add regression and TAP tests to verify the functionality.

This hardening measure allows administrators to disable COPY ... PROGRAM
at the server level as a defense-in-depth control. The enable_copy_program
parameter requires a server restart to take effect and cannot be altered
via ALTER SYSTEM.
---
 doc/src/sgml/config.sgml                      | 21 +++++++
 doc/src/sgml/ref/copy.sgml                    |  4 +-
 src/backend/commands/copy.c                   | 10 +++
 src/backend/utils/misc/guc_parameters.dat     |  8 +++
 src/backend/utils/misc/postgresql.conf.sample |  1 +
 src/bin/psql/copy.c                           |  2 +-
 src/include/utils/guc.h                       |  1 +
 src/test/recovery/meson.build                 |  1 +
 src/test/recovery/t/050_copy_program.pl       | 62 +++++++++++++++++++
 src/test/regress/expected/copy.out            | 11 ++++
 src/test/regress/expected/sysviews.out        |  3 +-
 src/test/regress/sql/copy.sql                 |  5 ++
 12 files changed, 126 insertions(+), 3 deletions(-)
 create mode 100644 src/test/recovery/t/050_copy_program.pl

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 737b90736bf..9b6575999cd 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1171,6 +1171,27 @@ include_dir 'conf.d'
       </listitem>
      </varlistentry>

+     <varlistentry id=3D"guc-enable-copy-program"
xreflabel=3D"enable_copy_program">
+      <term><varname>enable_copy_program</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>enable_copy_program</varname> configuration
parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Controls whether <command>COPY ... PROGRAM</command> is allowed.
The
+        default is <literal>on</literal>; when set to
<literal>off</literal>,
+        attempts to use <literal>PROGRAM</literal> are rejected even for
+        superusers or roles with
<literal>pg_execute_server_program</literal>.
+        This setting does not affect <command>\copy</command> or
+        <command>COPY</command> to or from
<literal>STDIN</literal>/<literal>STDOUT</literal>.
+        Changes require a server restart and cannot be made with
+        <command>ALTER SYSTEM</command>. This is a hardening measure, but
not a security
+        boundary; superusers retain other ways to execute operating system
commands.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id=3D"guc-krb-server-keyfile"
xreflabel=3D"krb_server_keyfile">
       <term><varname>krb_server_keyfile</varname> (<type>string</type>)
       <indexterm>
diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 53b0ea8f573..e7a02e8403d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -590,7 +590,9 @@ COPY <replaceable class=3D"parameter">count</replaceabl=
e>
     <literal>pg_write_server_files</literal>,
     or <literal>pg_execute_server_program</literal>, since it allows
reading
     or writing any file or running a program that the server has
privileges to
-    access.
+    access.  To disable program execution for <command>COPY</command>, set
+    <xref linkend=3D"guc-enable-copy-program"/> to <literal>off</literal>
+    (restart required).
    </para>

    <para>
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 28e878c3688..63fa55f631d 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -39,6 +39,9 @@
 #include "utils/rel.h"
 #include "utils/rls.h"

+/* Controls whether COPY PROGRAM is permitted at all. */
+bool enable_copy_program =3D true;
+
 /*
  * DoCopy executes the SQL COPY statement
  *
@@ -78,6 +81,13 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
  {
  if (stmt->is_program)
  {
+ if (!enable_copy_program)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("COPY PROGRAM is disabled"),
+ errhint("Set enable_copy_program =3D on to allow COPY "
+ "TO/FROM PROGRAM.")));
+
  if (!has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM))
  ereport(ERROR,
  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
diff --git a/src/backend/utils/misc/guc_parameters.dat
b/src/backend/utils/misc/guc_parameters.dat
index 3b9d8349078..22f0618ea58 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -819,6 +819,14 @@
   boot_val =3D> 'true',
 },

+{ name =3D> 'enable_copy_program', type =3D> 'bool', context =3D>
'PGC_POSTMASTER', group =3D> 'CONN_AUTH_AUTH',
+  short_desc =3D> 'Enables COPY to and from an external program.',
+  long_desc =3D> 'When disabled, COPY PROGRAM is rejected even for
superusers.  This can only be changed at server start.',
+  flags =3D> 'GUC_SUPERUSER_ONLY | GUC_DISALLOW_IN_AUTO_FILE',
+  variable =3D> 'enable_copy_program',
+  boot_val =3D> 'true',
+},
+
 { name =3D> 'enable_distinct_reordering', type =3D> 'bool', context =3D>
'PGC_USERSET', group =3D> 'QUERY_TUNING_METHOD',
   short_desc =3D> 'Enables reordering of DISTINCT keys.',
   flags =3D> 'GUC_EXPLAIN',
diff --git a/src/backend/utils/misc/postgresql.conf.sample
b/src/backend/utils/misc/postgresql.conf.sample
index dc9e2255f8a..7f3a2a63766 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -97,6 +97,7 @@
 #password_encryption =3D scram-sha-256    # scram-sha-256 or (deprecated) =
md5
 #scram_iterations =3D 4096
 #md5_password_warnings =3D on             # display md5 deprecation warnin=
gs?
+#enable_copy_program =3D on               # allow COPY ... PROGRAM command=
s
(restart)
 #oauth_validator_libraries =3D '' # comma-separated list of trusted
validator modules

 # GSSAPI using Kerberos
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 92c955b637a..04553c3a33f 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -33,7 +33,7 @@
  * \copy ( query stmt ) to filename [options]
  *
  * where 'filename' can be one of the following:
- * '<file path>' | PROGRAM '<command>' | stdin | stdout | pstdout | pstdou=
t
+ * '<file path>' | PROGRAM '<command>' | stdin | stdout | pstdin | pstdout
  * and 'query' can be one of the following:
  * SELECT | UPDATE | INSERT | DELETE
  *
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index f21ec37da89..a19c3ebb2a6 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -291,6 +291,7 @@ extern PGDLLIMPORT bool check_function_bodies;
 extern PGDLLIMPORT bool current_role_is_superuser;

 extern PGDLLIMPORT bool AllowAlterSystem;
+extern PGDLLIMPORT bool enable_copy_program;
 extern PGDLLIMPORT bool log_duration;
 extern PGDLLIMPORT int log_parameter_max_length;
 extern PGDLLIMPORT int log_parameter_max_length_on_error;
diff --git a/src/test/recovery/meson.build b/src/test/recovery/meson.build
index 523a5cd5b52..4055b782e30 100644
--- a/src/test/recovery/meson.build
+++ b/src/test/recovery/meson.build
@@ -58,6 +58,7 @@ tests +=3D {
       't/047_checkpoint_physical_slot.pl',
       't/048_vacuum_horizon_floor.pl',
       't/049_wait_for_lsn.pl',
+      't/050_copy_program.pl',
     ],
   },
 }
diff --git a/src/test/recovery/t/050_copy_program.pl b/src/test/recovery/t/
050_copy_program.pl
new file mode 100644
index 00000000000..5ec6c146377
--- /dev/null
+++ b/src/test/recovery/t/050_copy_program.pl
@@ -0,0 +1,62 @@
+#
+# Verify COPY PROGRAM behavior when enabled.
+#
+
+use strict;
+use warnings;
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node_on =3D PostgreSQL::Test::Cluster->new('enable_copy_program_on');
+$node_on->init;
+$node_on->start;
+
+# use perl as the external program for portability; $^X is portable enough
+my $perlbin =3D $^X;
+my $out_file =3D $node_on->basedir . '/enable_copy_program.out';
+
+# COPY ... TO PROGRAM should succeed when enabled.
+$node_on->safe_psql(
+ 'postgres',
+ "COPY (SELECT 42) TO PROGRAM "
+  . "'$perlbin -e \"print qq(42\\\\n)\" > $out_file'"
+);
+is(slurp_file($out_file), "42\n",
+ 'COPY TO PROGRAM writes to external program when enabled');
+
+# COPY ... FROM PROGRAM should succeed when enabled.
+my $in_prog =3D $node_on->basedir . '/enable_copy_program.sh';
+append_to_file($in_prog, "printf \"99\\n\";\n");
+chmod 0755, $in_prog or die "chmod failed for $in_prog: $!";
+$node_on->safe_psql('postgres', "CREATE TABLE copy_program_enabled(a
int)");
+$node_on->safe_psql('postgres',
+ "COPY copy_program_enabled FROM PROGRAM '$in_prog'");
+is(
+ $node_on->safe_psql('postgres',
+ "TABLE copy_program_enabled ORDER BY 1"),
+ "99",
+ 'COPY FROM PROGRAM reads from external program when enabled');
+
+# COPY PROGRAM can be disabled at postmaster start.
+my $node_off =3D PostgreSQL::Test::Cluster->new('enable_copy_program_off')=
;
+$node_off->init;
+$node_off->append_conf('postgresql.conf', "enable_copy_program=3Doff");
+$node_off->start;
+my $should_not_write =3D $node_off->basedir . '/should_not_write';
+my ($ret, $stdout, $stderr) =3D $node_off->psql(
+ 'postgres',
+ "COPY (SELECT 1) TO PROGRAM "
+  . "'$perlbin -e \"print qq(1\\\\n)\" > $should_not_write'"
+);
+isnt($ret, 0, 'COPY PROGRAM fails when disabled');
+like(
+ $stderr,
+ qr/COPY PROGRAM is disabled/,
+ 'COPY PROGRAM disabled error shown');
+
+$node_on->stop;
+$node_off->stop;
+
+done_testing();
diff --git a/src/test/regress/expected/copy.out
b/src/test/regress/expected/copy.out
index 24e0f472f14..1034f6431f7 100644
--- a/src/test/regress/expected/copy.out
+++ b/src/test/regress/expected/copy.out
@@ -393,3 +393,14 @@ id val
 5 15
 6 16
 DROP TABLE PP;
+-- COPY PROGRAM guard is postmaster-only and not alterable at runtime
+SHOW enable_copy_program;
+ enable_copy_program
+---------------------
+ on
+(1 row)
+
+ALTER SYSTEM SET enable_copy_program =3D off;  -- fail (auto conf)
+ERROR:  parameter "enable_copy_program" cannot be changed
+SET enable_copy_program =3D off;  -- fail (postmaster)
+ERROR:  parameter "enable_copy_program" cannot be changed without
restarting the server
diff --git a/src/test/regress/expected/sysviews.out
b/src/test/regress/expected/sysviews.out
index 3b37fafa65b..ac1ba6522f3 100644
--- a/src/test/regress/expected/sysviews.out
+++ b/src/test/regress/expected/sysviews.out
@@ -150,6 +150,7 @@ select name, setting from pg_settings where name like
'enable%';
 --------------------------------+---------
  enable_async_append            | on
  enable_bitmapscan              | on
+ enable_copy_program            | on
  enable_distinct_reordering     | on
  enable_eager_aggregate         | on
  enable_gathermerge             | on
@@ -173,7 +174,7 @@ select name, setting from pg_settings where name like
'enable%';
  enable_seqscan                 | on
  enable_sort                    | on
  enable_tidscan                 | on
-(25 rows)
+(26 rows)

 -- There are always wait event descriptions for various types.
InjectionPoint
 -- may be present or absent, depending on history since last postmaster
start.
diff --git a/src/test/regress/sql/copy.sql b/src/test/regress/sql/copy.sql
index 676a8b342b5..c98a6564479 100644
--- a/src/test/regress/sql/copy.sql
+++ b/src/test/regress/sql/copy.sql
@@ -419,3 +419,8 @@ CREATE TABLE pp_510 PARTITION OF pp_2 FOR VALUES FROM
(5) TO (10);
 INSERT INTO pp SELECT g, 10 + g FROM generate_series(1,6) g;
 COPY pp TO stdout(header);
 DROP TABLE PP;
+
+-- COPY PROGRAM guard is postmaster-only and not alterable at runtime
+SHOW enable_copy_program;
+ALTER SYSTEM SET enable_copy_program =3D off;  -- fail (auto conf)
+SET enable_copy_program =3D off;  -- fail (postmaster)
--=20
2.43.0

--00000000000028f151064509ce27
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div><font face=3D"monospace">Hi Postgres hackers,<br><br>=
Attached is a patch that introduces a new server-level configuration<br>par=
ameter, &quot;enable_copy_program&quot;, that allows administrators to disa=
ble<br>COPY ... PROGRAM functionality at the PostgreSQL server level.<br><b=
r><br>MOTIVATION<br>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<br><br>COPY ... PROGRAM =
is a powerful feature that allows executing arbitrary<br>shell commands fro=
m within PostgreSQL. While access is controlled via<br>the pg_execute_serve=
r_program role, some deployments may want to<br>completely disable this cap=
ability as a defense-in-depth measure.<br>This GUC provides that option.<br=
><br>In practice, COPY ... PROGRAM is a common code execution vector in<br>=
PostgreSQL-based attacks. It is:<br><br>=C2=A0 - Simple to use (single SQL =
statement)<br>=C2=A0 - Requires no additional extensions or setup<br>=C2=A0=
 - Frequently targeted by automated botnets and malware campaigns<br>=C2=A0=
 - Often the first technique attempted by attackers who gain superuser acce=
ss<br><br>While this GUC is not a comprehensive security solution, it serve=
s as a<br>mitigating control that removes some of the lowest-hanging fruit =
for<br>attackers.<br><br><br>IMPORTANT SECURITY CONTEXT<br>=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<br><br>This=
 is a mitigating control, not a security boundary.<br><br>There is ongoing =
ecosystem friction around the disputed CVE-2019-9193 entry <br>in the NVD. =
The PostgreSQL Security Team has stated that this CVE does not <br>represen=
t a security bug in PostgreSQL and was filed in error, but NVD and <br>othe=
r CVE databases still list it as a remote code execution issue via COPY <br=
>TO/FROM PROGRAM, and several commercial scanners and IDS/IPS signatures tr=
eat <br>it as a high-severity vulnerability. This patch is not intended as =
a fix for <br>that CVE; it simply provides an explicit configuration knob f=
or administrators <br>whose security tooling or policies require disabling =
program execution via COPY.<br><br>Superusers retain multiple other avenues=
 for executing operating system<br>commands, including but not limited to:<=
br><br>=C2=A0 - Untrusted procedural languages (CREATE EXTENSION plpythonu,=
 plperlu, etc.)<br>=C2=A0 - Custom extensions that provide shell access<br>=
=C2=A0 - The LOAD command to load arbitrary shared libraries<br>=C2=A0 - pg=
_read_file() / pg_write_file() combined with other techniques<br>=C2=A0 - F=
oreign data wrappers with program execution capabilities<br>=C2=A0 - Backgr=
ound workers in custom extensions<br><br>Disabling COPY ... PROGRAM does NO=
T make PostgreSQL secure against a<br>malicious superuser. However, it does=
:<br><br>=C2=A0 1. Block a very common and highly automated attack vector =
=E2=80=93 many botnet<br>=C2=A0 =C2=A0 =C2=A0payloads and exploit scripts s=
pecifically target COPY ... PROGRAM<br>=C2=A0 =C2=A0 =C2=A0because it requi=
res no prerequisites.<br><br>=C2=A0 2. Raise the bar for exploitation =E2=
=80=93 attackers must use more complex,<br>=C2=A0 =C2=A0 =C2=A0less portabl=
e, or more detectable methods.<br><br>=C2=A0 3. Reduce drive-by attacks =E2=
=80=93 automated scanners and opportunistic<br>=C2=A0 =C2=A0 =C2=A0attacker=
s often give up when their standard payload fails.<br><br>=C2=A0 4. Help me=
et compliance requirements =E2=80=93 some security frameworks mandate<br>=
=C2=A0 =C2=A0 =C2=A0disabling specific high-risk features.<br><br>=C2=A0 5.=
 Provide defense in depth =E2=80=93 one layer in a broader security strateg=
y.<br><br><br>KEY CHANGES<br>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<br><br>New G=
UC parameter:<br><br>=C2=A0 - Name: enable_copy_program<br>=C2=A0 - Type: b=
oolean<br>=C2=A0 - Default: on (preserves existing behavior)<br>=C2=A0 - Co=
ntext: PGC_POSTMASTER (requires server restart to change)<br>=C2=A0 - Flags=
: GUC_SUPERUSER_ONLY | GUC_DISALLOW_IN_AUTO_FILE<br><br>Implementation:<br>=
<br>=C2=A0 - copy.c<br>=C2=A0 =C2=A0 =C2=A0 * Add a check in DoCopy() to re=
ject COPY PROGRAM when disabled.<br>=C2=A0 - guc_parameters.dat<br>=C2=A0 =
=C2=A0 =C2=A0 * Register the new GUC parameter.<br>=C2=A0 - guc.h<br>=C2=A0=
 =C2=A0 =C2=A0 * Declare the enable_copy_program variable.<br><br>Documenta=
tion:<br><br>=C2=A0 - config.sgml<br>=C2=A0 =C2=A0 =C2=A0 * Document the pa=
rameter in the authentication section, including its<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 scope and limitations.<br>=C2=A0 - copy.sgml<br>=C2=A0 =C2=A0 =
=C2=A0 * Cross-reference the new parameter in the COPY command documentatio=
n.<br>=C2=A0 - postgresql.conf.sample<br>=C2=A0 =C2=A0 =C2=A0 * Add a comme=
nted sample entry.<br><br>Tests:<br><br>=C2=A0 - copy.sql (regression tests=
) verifying:<br>=C2=A0 =C2=A0 =C2=A0 * Default value is &quot;on&quot;.<br>=
=C2=A0 =C2=A0 =C2=A0 * ALTER SYSTEM SET is rejected (due to GUC_DISALLOW_IN=
_AUTO_FILE).<br>=C2=A0 =C2=A0 =C2=A0 * SET is rejected (due to PGC_POSTMAST=
ER context).<br>=C2=A0 - t/<a href=3D"http://050_copy_program.pl">050_copy_=
program.pl</a> (TAP test) verifying:<br>=C2=A0 =C2=A0 =C2=A0 * COPY TO PROG=
RAM works when enabled.<br>=C2=A0 =C2=A0 =C2=A0 * COPY FROM PROGRAM works w=
hen enabled.<br>=C2=A0 =C2=A0 =C2=A0 * Both are rejected with the expected =
error when disabled.<br>=C2=A0 - Updated expected output files accordingly.=
<br><br>Misc:<br><br>=C2=A0 - Fixed a typo in a copy.c comment:<br>=C2=A0 =
=C2=A0 =C2=A0 * &quot;pstdout | pstdout&quot; -&gt; &quot;pstdin | pstdout&=
quot;.<br><br><br>BEHAVIOR<br>=3D=3D=3D=3D=3D=3D=3D=3D<br><br>=C2=A0 enable=
_copy_program =C2=A0 COPY PROGRAM behavior<br>=C2=A0 ------------------- =
=C2=A0 ------------------------------------------<br>=C2=A0 on (default) =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Allowed (subject to role privileges)<br>=
=C2=A0 off =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 R=
ejected with error, even for superusers<br><br>Error message when disabled:=
<br><br>=C2=A0 ERROR: =C2=A0COPY PROGRAM is disabled<br>=C2=A0 HINT: =C2=A0=
 Set enable_copy_program =3D on to allow COPY TO/FROM PROGRAM.<br><br><br>T=
ESTING<br>=3D=3D=3D=3D=3D=3D=3D<br><br>=C2=A0 - All regression tests pass.<=
br>=C2=A0 - Recovery TAP tests pass (injection-point skips are expected).<b=
r>=C2=A0 - New TAP test t/<a href=3D"http://050_copy_program.pl">050_copy_p=
rogram.pl</a> validates both enabled and<br>=C2=A0 =C2=A0 disabled scenario=
s.<br><br><br>BACKWARD COMPATIBILITY<br>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<br><br>This change is fully backward comp=
atible. The default value &quot;on&quot;<br>preserves existing behavior. No=
 action is required for existing<br>deployments unless they wish to disable=
 COPY PROGRAM.<br><br>--<br>Ignat Remizov<br><br><br>From c642f17d0b44112ba=
5426be6412004e03d1a5e03 Mon Sep 17 00:00:00 2001<br>From: Ignat Remizov &lt=
;<a href=3D"mailto:ignat980@gmail.com">ignat980@gmail.com</a>&gt;<br>Date: =
Wed, 3 Dec 2025 11:01:31 +0200<br>Subject: [PATCH] Add enable_copy_program =
GUC to control COPY PROGRAM<br><br>Introduce a new postmaster-only GUC para=
meter enable_copy_program to<br>control the use of COPY ... PROGRAM. By def=
ault this parameter is set<br>to on, allowing the use of COPY ... PROGRAM a=
nd preserving existing<br>behavior. When set to off, attempts to use COPY .=
.. PROGRAM are<br>rejected, even for superusers or roles with the pg_execut=
e_server_program<br>privilege.<br><br>Key changes:<br>- Add enable_copy_pro=
gram as a postmaster-only GUC parameter.<br>- Update COPY command logic to =
enforce the enable_copy_program setting.<br>- Update documentation to refle=
ct the new parameter and its behavior.<br>- Add regression and TAP tests to=
 verify the functionality.<br><br>This hardening measure allows administrat=
ors to disable COPY ... PROGRAM<br>at the server level as a defense-in-dept=
h control. The enable_copy_program<br>parameter requires a server restart t=
o take effect and cannot be altered<br>via ALTER SYSTEM.<br>---<br>=C2=A0do=
c/src/sgml/config.sgml =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0| 21 +++++++<br>=C2=A0doc/src/sgml/ref/copy.sgml =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| =C2=
=A04 +-<br>=C2=A0src/backend/commands/copy.c =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | 10 +++<br>=C2=A0src/backend/utils/misc=
/guc_parameters.dat =C2=A0 =C2=A0 | =C2=A08 +++<br>=C2=A0src/backend/utils/=
misc/postgresql.conf.sample | =C2=A01 +<br>=C2=A0src/bin/psql/copy.c =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 | =C2=A02 +-<br>=C2=A0src/include/utils/guc.h =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A01 +<br>=
=C2=A0src/test/recovery/meson.build =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 | =C2=A01 +<br>=C2=A0src/test/recovery/t/<a href=3D"http:=
//050_copy_program.pl">050_copy_program.pl</a> =C2=A0 =C2=A0 =C2=A0 | 62 ++=
+++++++++++++++++<br>=C2=A0src/test/regress/expected/copy.out =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0| 11 ++++<br>=C2=A0src/test/regress/expected/sy=
sviews.out =C2=A0 =C2=A0 =C2=A0 =C2=A0| =C2=A03 +-<br>=C2=A0src/test/regres=
s/sql/copy.sql =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =
=C2=A05 ++<br>=C2=A012 files changed, 126 insertions(+), 3 deletions(-)<br>=
=C2=A0create mode 100644 src/test/recovery/t/<a href=3D"http://050_copy_pro=
gram.pl">050_copy_program.pl</a><br><br>diff --git a/doc/src/sgml/config.sg=
ml b/doc/src/sgml/config.sgml<br>index 737b90736bf..9b6575999cd 100644<br>-=
-- a/doc/src/sgml/config.sgml<br>+++ b/doc/src/sgml/config.sgml<br>@@ -1171=
,6 +1171,27 @@ include_dir &#39;conf.d&#39;<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0&=
lt;/listitem&gt;<br>=C2=A0 =C2=A0 =C2=A0 &lt;/varlistentry&gt;<br>=C2=A0<br=
>+ =C2=A0 =C2=A0 &lt;varlistentry id=3D&quot;guc-enable-copy-program&quot; =
xreflabel=3D&quot;enable_copy_program&quot;&gt;<br>+ =C2=A0 =C2=A0 =C2=A0&l=
t;term&gt;&lt;varname&gt;enable_copy_program&lt;/varname&gt; (&lt;type&gt;b=
oolean&lt;/type&gt;)<br>+ =C2=A0 =C2=A0 =C2=A0&lt;indexterm&gt;<br>+ =C2=A0=
 =C2=A0 =C2=A0 &lt;primary&gt;&lt;varname&gt;enable_copy_program&lt;/varnam=
e&gt; configuration parameter&lt;/primary&gt;<br>+ =C2=A0 =C2=A0 =C2=A0&lt;=
/indexterm&gt;<br>+ =C2=A0 =C2=A0 =C2=A0&lt;/term&gt;<br>+ =C2=A0 =C2=A0 =
=C2=A0&lt;listitem&gt;<br>+ =C2=A0 =C2=A0 =C2=A0 &lt;para&gt;<br>+ =C2=A0 =
=C2=A0 =C2=A0 =C2=A0Controls whether &lt;command&gt;COPY ... PROGRAM&lt;/co=
mmand&gt; is allowed.=C2=A0 The<br>+ =C2=A0 =C2=A0 =C2=A0 =C2=A0default is =
&lt;literal&gt;on&lt;/literal&gt;; when set to &lt;literal&gt;off&lt;/liter=
al&gt;,<br>+ =C2=A0 =C2=A0 =C2=A0 =C2=A0attempts to use &lt;literal&gt;PROG=
RAM&lt;/literal&gt; are rejected even for<br>+ =C2=A0 =C2=A0 =C2=A0 =C2=A0s=
uperusers or roles with &lt;literal&gt;pg_execute_server_program&lt;/litera=
l&gt;.<br>+ =C2=A0 =C2=A0 =C2=A0 =C2=A0This setting does not affect &lt;com=
mand&gt;\copy&lt;/command&gt; or<br>+ =C2=A0 =C2=A0 =C2=A0 =C2=A0&lt;comman=
d&gt;COPY&lt;/command&gt; to or from &lt;literal&gt;STDIN&lt;/literal&gt;/&=
lt;literal&gt;STDOUT&lt;/literal&gt;.<br>+ =C2=A0 =C2=A0 =C2=A0 =C2=A0Chang=
es require a server restart and cannot be made with<br>+ =C2=A0 =C2=A0 =C2=
=A0 =C2=A0&lt;command&gt;ALTER SYSTEM&lt;/command&gt;. This is a hardening =
measure, but not a security <br>+ =C2=A0 =C2=A0 =C2=A0 =C2=A0boundary; supe=
rusers retain other ways to execute operating system commands.<br>+ =C2=A0 =
=C2=A0 =C2=A0 &lt;/para&gt;<br>+ =C2=A0 =C2=A0 =C2=A0&lt;/listitem&gt;<br>+=
 =C2=A0 =C2=A0 &lt;/varlistentry&gt;<br>+<br>=C2=A0 =C2=A0 =C2=A0 &lt;varli=
stentry id=3D&quot;guc-krb-server-keyfile&quot; xreflabel=3D&quot;krb_serve=
r_keyfile&quot;&gt;<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0&lt;term&gt;&lt;varname&g=
t;krb_server_keyfile&lt;/varname&gt; (&lt;type&gt;string&lt;/type&gt;)<br>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0&lt;indexterm&gt;<br>diff --git a/doc/src/sgml/r=
ef/copy.sgml b/doc/src/sgml/ref/copy.sgml<br>index 53b0ea8f573..e7a02e8403d=
 100644<br>--- a/doc/src/sgml/ref/copy.sgml<br>+++ b/doc/src/sgml/ref/copy.=
sgml<br>@@ -590,7 +590,9 @@ COPY &lt;replaceable class=3D&quot;parameter&qu=
ot;&gt;count&lt;/replaceable&gt;<br>=C2=A0 =C2=A0 =C2=A0&lt;literal&gt;pg_w=
rite_server_files&lt;/literal&gt;,<br>=C2=A0 =C2=A0 =C2=A0or &lt;literal&gt=
;pg_execute_server_program&lt;/literal&gt;, since it allows reading<br>=C2=
=A0 =C2=A0 =C2=A0or writing any file or running a program that the server h=
as privileges to<br>- =C2=A0 =C2=A0access.<br>+ =C2=A0 =C2=A0access.=C2=A0 =
To disable program execution for &lt;command&gt;COPY&lt;/command&gt;, set<b=
r>+ =C2=A0 =C2=A0&lt;xref linkend=3D&quot;guc-enable-copy-program&quot;/&gt=
; to &lt;literal&gt;off&lt;/literal&gt;<br>+ =C2=A0 =C2=A0(restart required=
).<br>=C2=A0 =C2=A0 &lt;/para&gt;<br>=C2=A0<br>=C2=A0 =C2=A0 &lt;para&gt;<b=
r>diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c<br=
>index 28e878c3688..63fa55f631d 100644<br>--- a/src/backend/commands/copy.c=
<br>+++ b/src/backend/commands/copy.c<br>@@ -39,6 +39,9 @@<br>=C2=A0#includ=
e &quot;utils/rel.h&quot;<br>=C2=A0#include &quot;utils/rls.h&quot;<br>=C2=
=A0<br>+/* Controls whether COPY PROGRAM is permitted at all. */<br>+bool		=
enable_copy_program =3D true;<br>+<br>=C2=A0/*<br>=C2=A0 *	 DoCopy executes=
 the SQL COPY statement<br>=C2=A0 *<br>@@ -78,6 +81,13 @@ DoCopy(ParseState=
 *pstate, const CopyStmt *stmt,<br>=C2=A0	{<br>=C2=A0		if (stmt-&gt;is_prog=
ram)<br>=C2=A0		{<br>+			if (!enable_copy_program)<br>+				ereport(ERROR,<b=
r>+						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),<br>+						 errmsg(&quot;=
COPY PROGRAM is disabled&quot;),<br>+						 errhint(&quot;Set enable_copy_p=
rogram =3D on to allow COPY &quot;<br>+								 &quot;TO/FROM PROGRAM.&quot=
;)));<br>+<br>=C2=A0			if (!has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_=
SERVER_PROGRAM))<br>=C2=A0				ereport(ERROR,<br>=C2=A0						(errcode(ERRCOD=
E_INSUFFICIENT_PRIVILEGE),<br>diff --git a/src/backend/utils/misc/guc_param=
eters.dat b/src/backend/utils/misc/guc_parameters.dat<br>index 3b9d8349078.=
.22f0618ea58 100644<br>--- a/src/backend/utils/misc/guc_parameters.dat<br>+=
++ b/src/backend/utils/misc/guc_parameters.dat<br>@@ -819,6 +819,14 @@<br>=
=C2=A0 =C2=A0boot_val =3D&gt; &#39;true&#39;,<br>=C2=A0},<br>=C2=A0<br>+{ n=
ame =3D&gt; &#39;enable_copy_program&#39;, type =3D&gt; &#39;bool&#39;, con=
text =3D&gt; &#39;PGC_POSTMASTER&#39;, group =3D&gt; &#39;CONN_AUTH_AUTH&#3=
9;,<br>+ =C2=A0short_desc =3D&gt; &#39;Enables COPY to and from an external=
 program.&#39;,<br>+ =C2=A0long_desc =3D&gt; &#39;When disabled, COPY PROGR=
AM is rejected even for superusers.=C2=A0 This can only be changed at serve=
r start.&#39;,<br>+ =C2=A0flags =3D&gt; &#39;GUC_SUPERUSER_ONLY | GUC_DISAL=
LOW_IN_AUTO_FILE&#39;,<br>+ =C2=A0variable =3D&gt; &#39;enable_copy_program=
&#39;,<br>+ =C2=A0boot_val =3D&gt; &#39;true&#39;,<br>+},<br>+<br>=C2=A0{ n=
ame =3D&gt; &#39;enable_distinct_reordering&#39;, type =3D&gt; &#39;bool&#3=
9;, context =3D&gt; &#39;PGC_USERSET&#39;, group =3D&gt; &#39;QUERY_TUNING_=
METHOD&#39;,<br>=C2=A0 =C2=A0short_desc =3D&gt; &#39;Enables reordering of =
DISTINCT keys.&#39;,<br>=C2=A0 =C2=A0flags =3D&gt; &#39;GUC_EXPLAIN&#39;,<b=
r>diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/=
utils/misc/postgresql.conf.sample<br>index dc9e2255f8a..7f3a2a63766 100644<=
br>--- a/src/backend/utils/misc/postgresql.conf.sample<br>+++ b/src/backend=
/utils/misc/postgresql.conf.sample<br>@@ -97,6 +97,7 @@<br>=C2=A0#password_=
encryption =3D scram-sha-256 =C2=A0 =C2=A0# scram-sha-256 or (deprecated) m=
d5<br>=C2=A0#scram_iterations =3D 4096<br>=C2=A0#md5_password_warnings =3D =
on =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 # display md5 deprecation warn=
ings?<br>+#enable_copy_program =3D on =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 # allow COPY ... PROGRAM commands (restart)<br>=C2=A0#oauth_v=
alidator_libraries =3D &#39;&#39; # comma-separated list of trusted validat=
or modules<br>=C2=A0<br>=C2=A0# GSSAPI using Kerberos<br>diff --git a/src/b=
in/psql/copy.c b/src/bin/psql/copy.c<br>index 92c955b637a..04553c3a33f 1006=
44<br>--- a/src/bin/psql/copy.c<br>+++ b/src/bin/psql/copy.c<br>@@ -33,7 +3=
3,7 @@<br>=C2=A0 *	\copy ( query stmt ) to filename [options]<br>=C2=A0 *<b=
r>=C2=A0 * where &#39;filename&#39; can be one of the following:<br>- *	&#3=
9;&lt;file path&gt;&#39; | PROGRAM &#39;&lt;command&gt;&#39; | stdin | stdo=
ut | pstdout | pstdout<br>+ *	&#39;&lt;file path&gt;&#39; | PROGRAM &#39;&l=
t;command&gt;&#39; | stdin | stdout | pstdin | pstdout<br>=C2=A0 * and &#39=
;query&#39; can be one of the following:<br>=C2=A0 *	SELECT | UPDATE | INSE=
RT | DELETE<br>=C2=A0 *<br>diff --git a/src/include/utils/guc.h b/src/inclu=
de/utils/guc.h<br>index f21ec37da89..a19c3ebb2a6 100644<br>--- a/src/includ=
e/utils/guc.h<br>+++ b/src/include/utils/guc.h<br>@@ -291,6 +291,7 @@ exter=
n PGDLLIMPORT bool check_function_bodies;<br>=C2=A0extern PGDLLIMPORT bool =
current_role_is_superuser;<br>=C2=A0<br>=C2=A0extern PGDLLIMPORT bool Allow=
AlterSystem;<br>+extern PGDLLIMPORT bool enable_copy_program;<br>=C2=A0exte=
rn PGDLLIMPORT bool log_duration;<br>=C2=A0extern PGDLLIMPORT int log_param=
eter_max_length;<br>=C2=A0extern PGDLLIMPORT int log_parameter_max_length_o=
n_error;<br>diff --git a/src/test/recovery/meson.build b/src/test/recovery/=
meson.build<br>index 523a5cd5b52..4055b782e30 100644<br>--- a/src/test/reco=
very/meson.build<br>+++ b/src/test/recovery/meson.build<br>@@ -58,6 +58,7 @=
@ tests +=3D {<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0&#39;t/<a href=3D"http://047_c=
heckpoint_physical_slot.pl">047_checkpoint_physical_slot.pl</a>&#39;,<br>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0&#39;t/<a href=3D"http://048_vacuum_horizon_floo=
r.pl">048_vacuum_horizon_floor.pl</a>&#39;,<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0&=
#39;t/<a href=3D"http://049_wait_for_lsn.pl">049_wait_for_lsn.pl</a>&#39;,<=
br>+ =C2=A0 =C2=A0 =C2=A0&#39;t/<a href=3D"http://050_copy_program.pl">050_=
copy_program.pl</a>&#39;,<br>=C2=A0 =C2=A0 =C2=A0],<br>=C2=A0 =C2=A0},<br>=
=C2=A0}<br>diff --git a/src/test/recovery/t/<a href=3D"http://050_copy_prog=
ram.pl">050_copy_program.pl</a> b/src/test/recovery/t/<a href=3D"http://050=
_copy_program.pl">050_copy_program.pl</a><br>new file mode 100644<br>index =
00000000000..5ec6c146377<br>--- /dev/null<br>+++ b/src/test/recovery/t/<a h=
ref=3D"http://050_copy_program.pl">050_copy_program.pl</a><br>@@ -0,0 +1,62=
 @@<br>+#<br>+# Verify COPY PROGRAM behavior when enabled.<br>+#<br>+<br>+u=
se strict;<br>+use warnings;<br>+<br>+use PostgreSQL::Test::Cluster;<br>+us=
e PostgreSQL::Test::Utils;<br>+use Test::More;<br>+<br>+my $node_on =3D Pos=
tgreSQL::Test::Cluster-&gt;new(&#39;enable_copy_program_on&#39;);<br>+$node=
_on-&gt;init;<br>+$node_on-&gt;start;<br>+<br>+# use perl as the external p=
rogram for portability; $^X is portable enough<br>+my $perlbin =3D $^X;<br>=
+my $out_file =3D $node_on-&gt;basedir . &#39;/enable_copy_program.out&#39;=
;<br>+<br>+# COPY ... TO PROGRAM should succeed when enabled.<br>+$node_on-=
&gt;safe_psql(<br>+	&#39;postgres&#39;,<br>+	&quot;COPY (SELECT 42) TO PROG=
RAM &quot;<br>+	 =C2=A0. &quot;&#39;$perlbin -e \&quot;print qq(42\\\\n)\&q=
uot; &gt; $out_file&#39;&quot;<br>+);<br>+is(slurp_file($out_file), &quot;4=
2\n&quot;,<br>+	&#39;COPY TO PROGRAM writes to external program when enable=
d&#39;);<br>+<br>+# COPY ... FROM PROGRAM should succeed when enabled.<br>+=
my $in_prog =3D $node_on-&gt;basedir . &#39;/enable_copy_program.sh&#39;;<b=
r>+append_to_file($in_prog, &quot;printf \&quot;99\\n\&quot;;\n&quot;);<br>=
+chmod 0755, $in_prog or die &quot;chmod failed for $in_prog: $!&quot;;<br>=
+$node_on-&gt;safe_psql(&#39;postgres&#39;, &quot;CREATE TABLE copy_program=
_enabled(a int)&quot;);<br>+$node_on-&gt;safe_psql(&#39;postgres&#39;,<br>+=
	&quot;COPY copy_program_enabled FROM PROGRAM &#39;$in_prog&#39;&quot;);<br=
>+is(<br>+	$node_on-&gt;safe_psql(&#39;postgres&#39;,<br>+		&quot;TABLE cop=
y_program_enabled ORDER BY 1&quot;),<br>+	&quot;99&quot;,<br>+	&#39;COPY FR=
OM PROGRAM reads from external program when enabled&#39;);<br>+<br>+# COPY =
PROGRAM can be disabled at postmaster start.<br>+my $node_off =3D PostgreSQ=
L::Test::Cluster-&gt;new(&#39;enable_copy_program_off&#39;);<br>+$node_off-=
&gt;init;<br>+$node_off-&gt;append_conf(&#39;postgresql.conf&#39;, &quot;en=
able_copy_program=3Doff&quot;);<br>+$node_off-&gt;start;<br>+my $should_not=
_write =3D $node_off-&gt;basedir . &#39;/should_not_write&#39;;<br>+my ($re=
t, $stdout, $stderr) =3D $node_off-&gt;psql(<br>+	&#39;postgres&#39;,<br>+	=
&quot;COPY (SELECT 1) TO PROGRAM &quot;<br>+	 =C2=A0. &quot;&#39;$perlbin -=
e \&quot;print qq(1\\\\n)\&quot; &gt; $should_not_write&#39;&quot;<br>+);<b=
r>+isnt($ret, 0, &#39;COPY PROGRAM fails when disabled&#39;);<br>+like(<br>=
+	$stderr,<br>+	qr/COPY PROGRAM is disabled/,<br>+	&#39;COPY PROGRAM disabl=
ed error shown&#39;);<br>+<br>+$node_on-&gt;stop;<br>+$node_off-&gt;stop;<b=
r>+<br>+done_testing();<br>diff --git a/src/test/regress/expected/copy.out =
b/src/test/regress/expected/copy.out<br>index 24e0f472f14..1034f6431f7 1006=
44<br>--- a/src/test/regress/expected/copy.out<br>+++ b/src/test/regress/ex=
pected/copy.out<br>@@ -393,3 +393,14 @@ id	val<br>=C2=A05	15<br>=C2=A06	16<=
br>=C2=A0DROP TABLE PP;<br>+-- COPY PROGRAM guard is postmaster-only and no=
t alterable at runtime<br>+SHOW enable_copy_program;<br>+ enable_copy_progr=
am <br>+---------------------<br>+ on<br>+(1 row)<br>+<br>+ALTER SYSTEM SET=
 enable_copy_program =3D off; =C2=A0-- fail (auto conf)<br>+ERROR: =C2=A0pa=
rameter &quot;enable_copy_program&quot; cannot be changed<br>+SET enable_co=
py_program =3D off; =C2=A0-- fail (postmaster)<br>+ERROR: =C2=A0parameter &=
quot;enable_copy_program&quot; cannot be changed without restarting the ser=
ver<br>diff --git a/src/test/regress/expected/sysviews.out b/src/test/regre=
ss/expected/sysviews.out<br>index 3b37fafa65b..ac1ba6522f3 100644<br>--- a/=
src/test/regress/expected/sysviews.out<br>+++ b/src/test/regress/expected/s=
ysviews.out<br>@@ -150,6 +150,7 @@ select name, setting from pg_settings wh=
ere name like &#39;enable%&#39;;<br>=C2=A0--------------------------------+=
---------<br>=C2=A0 enable_async_append =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0| on<br>=C2=A0 enable_bitmapscan =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0| on<br>+ enable_copy_program =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0| on<br>=C2=A0 enable_distinct_reordering =C2=A0 =C2=A0 | on<br>=
=C2=A0 enable_eager_aggregate =C2=A0 =C2=A0 =C2=A0 =C2=A0 | on<br>=C2=A0 en=
able_gathermerge =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | on<br>@@ -173,=
7 +174,7 @@ select name, setting from pg_settings where name like &#39;enab=
le%&#39;;<br>=C2=A0 enable_seqscan =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 | on<br>=C2=A0 enable_sort =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| on<br>=C2=A0 enable_tidscan =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | on<br>-(25 rows)<br>=
+(26 rows)<br>=C2=A0<br>=C2=A0-- There are always wait event descriptions f=
or various types.=C2=A0 InjectionPoint<br>=C2=A0-- may be present or absent=
, depending on history since last postmaster start.<br>diff --git a/src/tes=
t/regress/sql/copy.sql b/src/test/regress/sql/copy.sql<br>index 676a8b342b5=
..c98a6564479 100644<br>--- a/src/test/regress/sql/copy.sql<br>+++ b/src/te=
st/regress/sql/copy.sql<br>@@ -419,3 +419,8 @@ CREATE TABLE pp_510 PARTITIO=
N OF pp_2 FOR VALUES FROM (5) TO (10);<br>=C2=A0INSERT INTO pp SELECT g, 10=
 + g FROM generate_series(1,6) g;<br>=C2=A0COPY pp TO stdout(header);<br>=
=C2=A0DROP TABLE PP;<br>+<br>+-- COPY PROGRAM guard is postmaster-only and =
not alterable at runtime<br>+SHOW enable_copy_program;<br>+ALTER SYSTEM SET=
 enable_copy_program =3D off; =C2=A0-- fail (auto conf)<br>+SET enable_copy=
_program =3D off; =C2=A0-- fail (postmaster)<br>-- <br>2.43.0<br></font><br=
></div><div><div dir=3D"ltr" class=3D"gmail_signature" data-smartmail=3D"gm=
ail_signature"><div dir=3D"ltr"><div><div></div></div></div></div></div></d=
iv>

--00000000000028f151064509ce27--