November 13, 2025·4 min read·engineeringpostgresqlsecuritypermissions

PostgreSQL 18.1 requires schema permission for statistics objects

CVE-2025-12817 let a table owner create statistics in a schema without permission and reserve another user's intended name. November's update also fixes allocation-size overflow in libpq.

Owning a table gives a role authority over that table. It should not grant authority to create named objects in every schema of the database. CVE-2025-12817 corrects a missing check in CREATE STATISTICS that had allowed exactly that, creating a way for one user to interfere with another user's database administration.

The November 13 announcement releases PostgreSQL 18.1, 17.7, 16.11, 15.15, 14.20 and 13.23. It includes two security corrections and more than fifty bug fixes. This is also PostgreSQL 13's final release, so applying 13.23 does not extend that major version's maintenance period.

PostgreSQL remains my default relational database, partly because its privilege model permits clear ownership boundaries. A command that operates on one object while creating another needs to respect both boundaries. This fix makes that requirement concrete for statistics used by the planner.

A statistics object has its own name and owner

The CREATE STATISTICS reference describes an object that tracks information about a table, foreign table or materialized view. The user issuing the command owns the statistics object. A schema-qualified name places it in the selected schema, and that name must be distinct from other statistics-object names there.

The command requires ownership of the source table. After creation, however, ownership of the statistics object is independent of the underlying relation. That distinction is why permission on the table cannot answer every authorization question involved in the operation.

Consider a role allowed to manage statistics for a table it owns. The privilege is meaningful within that table's administration. If the same operation can place a named object into another user's schema, it also affects a namespace that the role was never authorized to modify. The missing check allowed those two kinds of authority to be conflated.

The exploit reserves a name in another schema

The CVE-2025-12817 advisory describes denial of service against another CREATE STATISTICS user. A table owner could create the statistics object in any schema. A later legitimate attempt to create an object with the same name would then fail because the name was already occupied.

This is not a claim that the attacker gains every privilege associated with that schema. The disclosed interference uses unauthorized object creation to cause a naming conflict. The fixed command checks for schema CREATE privilege before permitting the operation.

PostgreSQL's schema documentation distinguishes USAGE from CREATE. Accessing objects in a schema and creating objects there are separate permissions. The distinction allows a schema owner to expose existing objects without allowing every reader to add new ones.

For statistics creation, the authorization conditions therefore concern both the source relation and the destination schema. Passing the table-ownership check does not establish destination permission. The repair applies the check appropriate to the new object, instead of treating the table operation as sufficient authorization for its placement.

IF NOT EXISTS cannot establish the intended definition

The command reference says IF NOT EXISTS considers the object's name, not the details of its definition. When the name exists, PostgreSQL issues a notice and does not create another object. That behavior is useful for some repeated administrative commands but cannot establish that an existing object matches the intended statistics definition.

This has a direct implication for the disclosed naming conflict. Replacing an error with an existence-tolerant command does not prove that the wanted statistical object was created. A name can be occupied by an object whose definition differs from the one the legitimate user requested.

The planner-statistics documentation explains that creating an extended statistics object declares which column relationships should be measured. ANALYZE performs the actual collection. A name-only existence check therefore cannot substitute for identifying the measurements the object requests.

I find that distinction useful in schema automation. Successful execution is insufficient evidence when the command intentionally accepts an existing name without comparing definitions. For this vulnerability, the authorization fix prevents unauthorized placement, while the object definition remains the evidence for what statistics the administrator requested.

The second security fix concerns client memory allocation

The CVE-2025-12818 advisory describes integer wraparound in several libpq functions. An application input provider or network peer can cause an undersized allocation followed by an out-of-bounds write, resulting in a segmentation fault in the client application.

The 18.1 release notes explain that sufficiently large inputs could overflow calculations for required buffer sizes. An allocated buffer would then be smaller than the subsequent write required. The correction addresses the arithmetic used to size allocations, rather than simply requiring the allocator to provide more memory.

This difference is important when interpreting failures. An out-of-memory rejection concerns a correctly computed request that cannot be satisfied. An overflow can turn a large required size into a smaller accepted allocation. Successful allocation does not make the later write fit, because the requested size no longer represents the actual input requirement.

Server and client updates need distinct evidence

The libpq miscellaneous-function reference documents PQlibVersion() as reporting the library being used at runtime. That is a client-library observation. It is distinct from querying the version of the PostgreSQL server to which the application connects.

The distinction matters in this release because the schema-permission correction belongs to server execution, while the allocation correction belongs to libpq. Installing a fixed database server does not establish which library an application has packaged or loaded. Each affected path needs evidence about the component executing it.

The November update follows the normal minor-release procedure without requiring a dump and reload. Its two security fixes still concern different authority and resource boundaries. CREATE STATISTICS must validate the destination schema, while libpq must compute an allocation size that represents the input it will write. The published fixed versions identify the replacement code for both paths.