From 3d2148a8213a689dd81c3edc3f3b08a4caf94000 Mon Sep 17 00:00:00 2001 From: Utkarash Kumar Singh Date: Fri, 4 Sep 2026 13:31:18 +0100 Subject: [PATCH] docs: add pgcrypto legacy-cipher caveat for the 15.19/17.11 upgrade (#49894) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Docs update — follow-up to #49621 for the Postgres 15.19 / 17.11 release. ## What is the current behavior? The upgrade guide covers three of the four customer-action items for this release; the pgcrypto legacy-cipher caveat (CVE-2026-14663) was deliberately held pending Security sign-off on the wording. ## What is the new behavior? Adds a "Pgcrypto legacy PGP ciphers" section (between the Ltree and Btree_gist sections, matching the release comms order): who is affected (`bf`/`blowfish`/`cast5` only), the wrong-key decrypt probe to check stored data, the AES re-encrypt step (with `ignore-cipher-failure=1` for post-upgrade recovery), and the secret-rotation recommendation. Wording approved by Security. ## Additional context Refs PSQL-1245 / PSQL-1110. Matches the customer email draft and changelog entry wording. ## Summary by CodeRabbit - **Documentation** - Updated `pgcrypto` upgrade guidance to separate pre-upgrade decryption from post-upgrade recovery, including the appropriate handling for cipher failures. - Added row-based targeting and plaintext spot checks before bulk updates. - Clarified that automated wrong-key scans cover symmetric messages; public-key messages require manual identification and key-pair re-encryption. - Updated the caution note to direct users to scan stored values rather than rely on a fixed list of cipher algorithms. No action is needed when `cipher-algo` was never specified. --- .../content/guides/platform/upgrading.mdx | 55 +++++++++++++++++++ supa-mdx-lint/Rule003Spelling.toml | 2 + 2 files changed, 57 insertions(+) diff --git a/apps/docs/content/guides/platform/upgrading.mdx b/apps/docs/content/guides/platform/upgrading.mdx index 13f873a7228..a98606b0c8e 100644 --- a/apps/docs/content/guides/platform/upgrading.mdx +++ b/apps/docs/content/guides/platform/upgrading.mdx @@ -286,6 +286,61 @@ Reindex each index it returns, using the schema-qualified name. `REINDEX INDEX C REINDEX INDEX CONCURRENTLY .; ``` +### Pgcrypto legacy PGP ciphers + +_Applies when upgrading to Postgres 15.19 or 17.11._ + + + +You are affected only if you call pgcrypto PGP functions with a `cipher-algo` that is unavailable in your server's OpenSSL build. The default cipher (AES) is not affected — if you never pass a `cipher-algo` option, no action is needed. Use the scan below to check stored values. + + + +This release fixes [CVE-2026-14663](https://www.postgresql.org/support/security/CVE-2026-14663/): previously, when a requested PGP cipher was unavailable in the server's OpenSSL build, pgcrypto did not apply it, so affected values were not protected as intended and can be decrypted even with the wrong key. After upgrading, decrypting such messages fails by default, and encrypting with those ciphers returns an error. + +To find affected rows, scan each stored value with a deliberately wrong passphrase: properly encrypted values raise an error, while affected values decrypt successfully even with the wrong key. Run the helper and the scan in the same session (`pg_temp` functions are session-scoped): + +```sql +create function pg_temp.affected_by_cve_2026_14663(msg bytea) +returns boolean +language plpgsql as $$ +begin + perform pgp_sym_decrypt_bytea(msg, 'deliberately-wrong-key'); + return true; +exception when others then + return false; +end $$; + +select +from +where is not null + and pg_temp.affected_by_cve_2026_14663(); +``` + +Any rows returned hold affected values. The scan covers symmetric (`pgp_sym_*`) messages; the wrong-key probe does not apply to public-key (`pgp_pub_*`) messages. If you call `pgp_pub_encrypt` with one of the affected `cipher-algo` options, treat those values as affected and re-encrypt them the same way using `pgp_pub_decrypt` and `pgp_pub_encrypt` with your key pair. + +Re-encrypt affected values with a modern cipher. Before you upgrade, the current version still decrypts them normally: + +```sql +update +set = pgp_sym_encrypt( + pgp_sym_decrypt(, ''), + '', 'cipher-algo=aes256') +where in (/* rows found by the scan above */); +``` + +After you upgrade, decrypting affected values fails by default — add `ignore-cipher-failure=1` to read them: + +```sql +update +set = pgp_sym_encrypt( + pgp_sym_decrypt(, '', 'ignore-cipher-failure=1'), + '', 'cipher-algo=aes256') +where in (/* rows found by the scan above */); +``` + +If the plaintext is binary (encrypted with `pgp_sym_encrypt_bytea`), use `pgp_sym_decrypt_bytea` and `pgp_sym_encrypt_bytea` in the same way — the text functions reject binary plaintext. Spot-check that a recovered value decrypts to the expected plaintext before running the update across all rows. Because affected values were not protected as intended, consider rotating any secrets stored this way. + ### Btree_gist indexes on float columns require reindexing after upgrade _Applies when upgrading to Postgres 15.19 or 17.11._ diff --git a/supa-mdx-lint/Rule003Spelling.toml b/supa-mdx-lint/Rule003Spelling.toml index 92480d7258b..ff0f5a9a612 100644 --- a/supa-mdx-lint/Rule003Spelling.toml +++ b/supa-mdx-lint/Rule003Spelling.toml @@ -350,6 +350,8 @@ allow_list = [ "PGroonga", "pg_basebackup", "PgBouncer", + "pgcrypto", + "Pgcrypto", "pgjwt", "PHI", "Pico",