November 12, 2020·4 min read·engineeringpostgresqlsecuritymaintenance

PostgreSQL 13.1 repairs privileged maintenance and client security

The November update closes a server privilege escalation and two client vulnerabilities. Safe maintenance depends on restricted execution, while clients must preserve connection policy and separate query data from control variables.

Administrative database work can execute expressions supplied by an object owner. A maintenance command therefore needs a restricted execution context even when a privileged administrator starts it. PostgreSQL 13.1 repairs an escape from that context. The November 12 release announcement recommends updating as soon as possible because of CVE-2020-25695, alongside two client security fixes and more than 65 ordinary bug fixes.

The release covers all supported major branches. Its security consequences do not depend on adopting PostgreSQL 13's new query features. An installation on an older supported major version can obtain the corresponding maintenance release. The announcement describes the cumulative update procedure without requiring dump and restore or pg_upgrade, while reminding users who skipped maintenance versions to consult earlier migration instructions.

I default to PostgreSQL for relational systems, and predictable administrative behaviour is part of that choice. Ownership boundaries need to survive maintenance operations. A person who owns a table may define expressions associated with it, but that should not grant the authority of a superuser who later maintains the object.

Restricted work could retain dangerous effects

The CVE-2020-25695 advisory identifies the prerequisite as permission to create non-temporary objects in at least one schema. An attacker with that permission could execute arbitrary SQL functions as a superuser. The affected maintained versions span 9.5 through 13, with fixes published in their November maintenance releases.

The 13.1 release notes in the tagged source identify the operations the repair blocks. Index expressions and materialized view queries must not declare holdable cursors or fire deferred triggers within the restricted operation. The problem is therefore more specific than an administrator intentionally invoking an untrusted function with elevated rights. The restricted operation was supposed to constrain what expression evaluation could arrange.

This matters for the meaning of routine maintenance. A table or index definition is input to a privileged operation, not evidence that all its behaviour is trusted. The existence of a restricted context acknowledges that distinction. The repair closes ways for expression evaluation to produce effects outside the intended restrictions.

The advisory's temporary workaround is correspondingly disruptive. It includes disabling autovacuum and avoiding several commands, including ANALYZE and index creation or rebuilding, until updating is possible. Ordinary VACUUM without FULL is safe, and operations on objects owned by trusted users are safe. The advisory warns that performance can degrade quickly under the workaround, which makes the maintenance update the practical remediation for most installations.

Additional connections lost security parameters

The second issue, CVE-2020-25694, concerns PostgreSQL client applications creating additional connections. Some retained basic connection fields while losing other parameters from the original connection string. Dropping sslmode or another security-relevant setting could permit cleartext transmission or an interception attack that the requested policy would have prevented.

The affected applications include pg_dump, pg_restore, vacuumdb and psql. Its prerequisite matters here too. The advisory limits the vulnerability to invocation with a connection string containing a security-relevant parameter. A successful first connection did not establish that every connection subsequently created by the program inherited the same security policy.

The fix also changes psql reconnection so non-overridden connection-string parameters remain in effect. That is a useful contract for an interactive administrator. Changing the database or another selected field should not silently discard an unrelated protection requested for the connection. Security policy is part of the connection configuration, alongside the destination and account.

I regard this as a client update requirement as well as a server maintenance task. A corrected database server cannot reconstruct options an older client discarded before establishing its next connection. The tools running backups and maintenance on another machine belong in the update inventory because those processes create the connections in question.

The libpq connection documentation illustrates why a connection string carries more information than a host and account. It can express multiple hosts, with corresponding ports, or a Unix socket directory. URI parameters can carry options that require percent encoding. Reconstructing a connection from a small subset of fields therefore loses part of the original request even before considering security.

For an administrator reading a command invocation, the full connection description is the evidence of intent. A report that the destination host stayed the same does not establish that the reconnection preserved the original policy. The maintenance tools need to retain the parameters they were given unless a documented override changes them.

Query output could become client configuration

The third issue, CVE-2020-25696, concerns psql's gset meta-command. A compromised server could return column names that overwrote specially handled client variables. In an interactive session this could lead to code execution under the operating system account running psql. A lowercase prefix avoids collision with those special variables in an unpatched client, according to the advisory.

The psql manual shipped with 13.1 explains the legitimate mechanism. The query must return exactly one row. Its column names become variable names, with an optional prefix prepended. A null unsets the corresponding variable. Failure or a result other than one row leaves variables unchanged.

For example, an ordinary script can store a result under an explicit lowercase prefix:

SELECT 42 AS item_count
\gset report_
\echo :report_item_count

This example creates report_item_count as a client variable. The prefix establishes a namespace for the query's data, separate from psql's special control names. Updating the client repairs the unsafe treatment of those special variables, while the prefixed form also makes the script's intended data variables easier to identify.

The mechanism explains why the server cannot automatically be trusted merely because a query appears to return data. A column name acquires operational meaning when a client maps it into configuration. The repair constrains that mapping at the point where query output enters psql's variable system. A backup connection, a maintenance expression and an interactive query result each require their own authority checks because they cross different boundaries.