Technical Analysis: Expanding refint Documentation with Usage Info
Core Problem
The refint contrib module (which provides referential integrity checking via triggers) has been the subject of multiple security reports to the PostgreSQL security team regarding potential SQL injection vulnerabilities through its trigger arguments. The fundamental issue is architectural: refint's trigger functions accept table and column names as unquoted string arguments, which are then used to construct SQL queries internally. This creates a theoretical SQL injection vector if an attacker could control those trigger argument values.
Security Context and Design Decision
During the preparation of CVE-2026-6637, the security team evaluated whether to forcibly quote these trigger arguments (i.e., apply quote_ident() or similar quoting to table/column name arguments before using them in constructed queries). They concluded this would be the wrong approach for several reasons:
-
Breakage risk exceeds exploit risk: Forcibly quoting arguments would likely break existing deployments that rely on the current unquoted behavior (e.g., mixed-case identifiers that are already properly handled by convention, or arguments containing schema-qualified names with dots).
-
Threat model mismatch: Unlike data values that come from untrusted user input, trigger arguments are specified in DDL statements (
CREATE TRIGGER). Only users with sufficient privileges to create triggers can set these values. There is no realistic attack scenario where an adversary who cannot already execute arbitrary SQL would be able to inject hostile values into trigger arguments. -
Defense-in-depth via documentation: Rather than a code change that risks regressions, the team opted for a documentation-only approach that clarifies the security expectations and proper usage patterns for
refint.
The Patch
The proposed patch is a documentation update that:
- Adds usage information to the
refintdocumentation explaining how trigger arguments should be specified - Clarifies security expectations around the trigger argument interface
- Is intended for back-patching to PostgreSQL v14 (indicating it's considered important enough to reach all supported branches)
The patch was originally scoped larger (to accompany CVE-2026-6637) but was trimmed to focus only on security-relevant documentation.
Broader Context: refint Deprecation
An important architectural note is that refint is being prepared for complete removal in PostgreSQL v20. This module is a legacy mechanism from before PostgreSQL had native FOREIGN KEY constraints. Native foreign keys are superior in every way:
- They're enforced at the catalog level
- They participate in query planning (join removal, etc.)
- They handle quoting and identifier resolution correctly
- They integrate with
pg_dump,ALTER TABLE, and the dependency system
The suggestion to mention deprecation in the documentation patch was acknowledged but deferred to the actual removal effort, keeping this patch focused on its original security-documentation scope.
Assessment
This is a straightforward, low-risk documentation improvement. The security team's decision to document rather than code-fix is sound given:
- The module is legacy and slated for removal
- The theoretical attack requires privileges that already grant full SQL execution
- Code changes would risk breaking existing users in stable branches
- Back-patching documentation is essentially zero-risk