From c0392783c541dac9e1148c5131882612fefaf9dc Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Mon, 8 Jun 2026 10:33:52 -0500 Subject: [PATCH] doc: Expand on proper use of refint. The security team has received a couple of reports about potential SQL injection via refint's trigger arguments. We discussed this while preparing CVE-2026-6637 and concluded that forcibly quoting these arguments is more likely to break working code than to prevent exploits. Unlike data values, the table/column names come from trigger arguments, and there is little reason for a trigger author to put hostile inputs into those arguments. So, let's document it accordingly. Reported-by: Nikolay Samokhvalov Reported-by: Alex Young Reported-by: Satyanarayana Narlapuram Suggested-by: Noah Misch Reviewed-by: Noah Misch Reviewed-by: Fujii Masao Reviewed-by: Christoph Berg Reviewed-by: Satyanarayana Narlapuram Discussion: https://postgr.es/m/ahXP7z7nsfGPOZ3T%40nathan Backpatch-through: 14 --- doc/src/sgml/contrib-spi.sgml | 58 ++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/contrib-spi.sgml b/doc/src/sgml/contrib-spi.sgml index e7cae4e38dc..54596a485be 100644 --- a/doc/src/sgml/contrib-spi.sgml +++ b/doc/src/sgml/contrib-spi.sgml @@ -34,6 +34,14 @@ key mechanism, of course, but the module is still useful as an example.) + + + refint requires a + secure schema usage pattern and + data types where the equality operator is named =. + + + check_primary_key() checks the referencing table. To use, create a BEFORE INSERT OR UPDATE trigger using this @@ -44,6 +52,29 @@ keys, create a trigger for each reference. + + + The referenced table name and column name arguments to + check_primary_key() are copied as-is into internally + generated SQL statements and therefore must be double-quoted by the user as + necessary in the CREATE TRIGGER command. See + for more information about quoting + SQL identifiers. Conversely, the referencing table + column name arguments should not be double quoted. See the following mock + example of proper use of check_primary_key(): + +CREATE TRIGGER mytrigger +BEFORE INSERT OR UPDATE ON referencing_table +FOR EACH ROW EXECUTE PROCEDURE +check_primary_key ( + 'column A', 'column B', -- referencing table columns + 'myschema."referenced table"', -- referenced table + '"column A"', '"column B"' -- referenced table columns +); + + + + check_foreign_key() checks the referenced table. To use, create a BEFORE DELETE OR UPDATE trigger using this @@ -53,13 +84,38 @@ (cascade — to delete the referencing row, restrict — to abort transaction if referencing keys exist, setnull — to set referencing key fields to null), - the triggered table's column names which form the primary/unique key, then + the referenced table's column names which form the primary/unique key, then the referencing table name and column names (repeated for as many referencing tables as were specified by first argument). Note that the primary/unique key columns should be marked NOT NULL and should have a unique index. + + + The referencing table name and column name arguments + to check_foreign_key() are copied as-is into + internally generated SQL statements and therefore must be double-quoted by + the user as necessary in the CREATE TRIGGER command. + See for more information about + quoting SQL identifiers. Conversely, the referenced + table column name arguments should not be double quoted. See the following + mock example of proper use of check_foreign_key(): + +CREATE TRIGGER mytrigger +BEFORE DELETE OR UPDATE ON referenced_table +FOR EACH ROW EXECUTE PROCEDURE +check_foreign_key ( + 1, -- number of referencing tables + 'cascade', -- action + 'column A', 'column B', -- referenced table columns + 'myschema."referencing table"', -- referencing table + '"column A"', '"column B"' -- referencing table columns +); + + + + There are examples in refint.example.