BUG #19714: pgcrypto pgp_sym_encrypt accepts nonnumeric s2k-mode as mode 0

Started by PG Bug reporting form14 days ago2 messagesbugs
Beta feature

Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.

appliessuccessCI history

You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:

docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253898
psql -h localhost -U postgres

Built from patchset v2 (message #2), October 06, 2026 at 07:52 AM.

Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:

git clone --branch t253898_2 https://github.com/hackorum-dev/postgres.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t253898_2 && git checkout t253898_2

Patchset v2 (message #2) is on t253898_2

Jump to latest
#1PG Bug reporting form
noreply@postgresql.org

The following bug has been logged on the website:

Bug reference: 19714
Logged by: Qifan Liu
Email address: imchifan@163.com
PostgreSQL version: 18.6
Operating system: Linux on amd64
Description:

pgp_sym_encrypt accepts the malformed option s2k-mode=not_a_number and
produces usable ciphertext. The documented s2k-mode values are numeric modes
0, 1, and 3, so nonnumeric text should be rejected rather than silently
selecting mode 0. This can cause encryption to use a different string-to-key
mode than the caller specified. The impact is localized to pgcrypto option
validation.

Steps to reproduce
------------------
CREATE EXTENSION pgcrypto;

SELECT pgp_sym_decrypt(
pgp_sym_encrypt('payload',
'key',
's2k-mode=not_a_number'),
'key') = 'payload' AS malformed_s2k_mode_accepted;

Actual result
-------------
malformed_s2k_mode_accepted
-----------------------------
t
(1 row)

The malformed value is accepted, and the produced ciphertext decrypts
successfully.

Expected result
---------------
pgp_sym_encrypt should reject s2k-mode=not_a_number with an error because
s2k-mode accepts only the documented numeric values. It should not interpret
malformed text as mode 0 or produce ciphertext.

Additional information
----------------------
The issue was reproduced on PostgreSQL 20devel, PostgreSQL 18.6, and
PostgreSQL 17.11.
Inference: the behavior is consistent with numeric conversion that maps text
without a valid numeric prefix to zero before validating the resulting mode.

#2shihao zhong
zhong950419@gmail.com
In reply to: PG Bug reporting form (#1)
Re: BUG #19714: pgcrypto pgp_sym_encrypt accepts nonnumeric s2k-mode as mode 0

Hi

All the integer PGP options are parsed with atoi(), so trailing junk
("s2k-mode=3x") and values that wrap around int ("s2k-mode=4294967299"
gives 3) get through too.

This is not a common case. It only happens when the caller writes a bad
option string, and *the caller could ask for mode 0 directly anyway,* so
it is not a security problem. The one case worth fixing is s2k-mode.
Junk there gives the unsalted mode 0, and decryption still works, so
nobody would notice. "s2k-mode=salted" is an easy mistake to make,
since the other S2K options take names.

0001 parses the values with strtoint() and raises the existing "Illegal
argument to function" error. 0002 adds tests and is optional.

This makes some inputs that work today fail, so I'd keep it to master.
I can do back-branch versions if a committer wants it back-patched.

Shihao

Attachments:

t253898_2
v1-0002-pgcrypto-Add-tests-for-malformed-integer-PGP-opti.patchapplication/octet-stream; name=v1-0002-pgcrypto-Add-tests-for-malformed-integer-PGP-opti.patchDownload+19-1
v1-0001-pgcrypto-Reject-malformed-integer-values-in-PGP-o.patchapplication/octet-stream; name=v1-0001-pgcrypto-Reject-malformed-integer-values-in-PGP-o.patchDownload+34-17