pg_ivm 1.5.1 repairs the authority used to maintain views
Incremental materialized views need consistent row visibility and name resolution. Two security fixes show how maintenance can violate either requirement.
Incrementally maintaining a materialized view means executing more database work whenever its source tables change. That work must preserve the view owner's authority as well as the query result. pg_ivm 1.5.1 fixes two ways the maintenance path could violate that requirement, exposing rows the owner could not read or resolving functions in an unintended schema.
The March 2 security announcement identifies CVE-2023-22847 for the row-security problem and CVE-2023-23554 for unsafe name resolution. It credits Yugo Nagata with the relevant corrections. These are extension defects, so the affected component is pg_ivm, rather than an assertion that PostgreSQL's built-in materialized views use this maintenance implementation.
I regard PostgreSQL's extension system as one of its strongest practical capabilities. This release also shows why an extension implementing privileged database behavior needs scrutiny comparable to the server code around it. The interesting boundary is the authority under which extra SQL runs after an application modifies a table.
Immediate maintenance adds work to the writing transaction
The version 1.5.1 documentation describes immediate incremental maintenance using AFTER triggers. An incrementally maintainable materialized view, or IMMV, changes within the transaction that modifies its base table. It does not wait for a scheduled refresh after commit. This avoids recomputing the entire result when only a small part changes.
The documented interface uses create_immv with a relation name and a defining query. Creating that relation also installs triggers to maintain it. The extension can create a unique index automatically when the view definition provides suitable keys. That index helps the maintenance code find existing result rows that need changes.
Immediate maintenance moves a cost into writes. The documentation says base-table updates become slower because their triggers also update the IMMV. Updating a small fraction of a table can make that worthwhile, while large modifications can cost more than rebuilding the result. The security issue exists inside this additional write-time execution, which needs the same access restrictions as the intended view computation.
Mixed commands could expose rows hidden from the owner
View maintenance runs with the view owner's privileges. When row-level security applies to a base table, the maintenance query must exclude rows that this owner cannot access. A different role modifying the base table does not authorize adding every row it can see to the owner's materialized result.
The announcement explains a failure when a query contains multiple command types. Its examples include a modifying common table expression combining INSERT and UPDATE, and a MERGE command. In those cases, incremental refresh could mishandle the row-security check and include rows that should have remained invisible to the IMMV owner.
The distinction between the writer and the owner is essential. Permission to modify a source table and permission to populate a particular view are different questions. An extension can legitimately switch execution privileges for maintenance, but the associated security checks must follow that switch. Otherwise a correct query definition can accumulate an incorrect set of visible rows through later maintenance.
This is also why testing only the initial view contents is insufficient to describe the failure. The announcement locates it in incremental refresh during particular compound modifications. A view that starts with the expected rows can violate its visibility restriction after a later statement takes that path. The correction makes row-security evaluation part of maintenance under the proper owner.
Function lookup can redirect privileged work
The second vulnerability concerns unqualified function names. Maintenance used functions in pg_catalog without specifying their schema. Under the conditions described in the announcement, PostgreSQL could resolve those names to functions in another schema. A user capable of creating a function could then arrange for unexpected code to run with the IMMV owner's privileges.
The release fixes that by qualifying the function names used during maintenance. This constrains which function the extension means to call. A privileged operation cannot safely infer its intended function solely from a caller-influenced search path when the operation expects a particular catalog implementation.
Cached queries for minimum and maximum aggregates required a related correction. The extension builds those plans from the textual view definition. When search_path changed, parsing that text again could select tables or functions in the wrong schema. The security release rebuilds from a new query string with appropriately qualified names under the latest path.
That detail explains why qualifying a few direct calls would not describe the complete fix. Name resolution also happens when stored query text becomes a new execution plan. Both paths must identify the intended objects while the extension operates with the owner's authority.
Aggregate maintenance explains the cached query
The versioned documentation gives useful context for the minimum and maximum path. When deletion removes a row supplying a group's current minimum or maximum, pg_ivm may need to recalculate that aggregate from the base tables. Incremental maintenance therefore includes cases that execute another query over the relevant group. It cannot always derive the replacement extremum from the previous aggregate value alone.
Other aggregates retain supporting data. The documentation describes extra columns for counts and sums, including information used to maintain an average. Those implementation details explain why maintenance involves more than copying the changed row into a result table. Each supported query form has its own stored state and execution requirements.
My interest in this release is the explicit connection between that machinery and authorization. The extension needs both the right mathematical update and the right set of permitted source rows. An aggregate calculated from unauthorized inputs is still a security failure even when the arithmetic is correct.
The versioned README also documents a separate policy-lifetime limitation. Creating or changing a row-security policy after creating an IMMV does not apply the new policy to its existing contents. Applying that policy requires recreating the IMMV. That documented behavior remains distinct from the vulnerability repaired here, which allowed incremental maintenance to disregard the owner's visibility under an applicable policy. Administrators need to account for stored view contents when changing policy as well as install the corrected maintenance code.