Postgres 17.11 pgcrypto change: verify a Sume webhook with hmac()
The Postgres minor release changed legacy pgcrypto ciphers. Its listed changes never mention hmac(), so a Sume sume-v1 signature check in SQL still works.

Yes, you can check a Sume signature in SQL, and the pgcrypto change in this release does not touch hmac(). The Supabase changelog's pgcrypto item concerns legacy ciphers, and it never mentions hmac, so I would still test after upgrading rather than assume.
Supabase and PostgreSQL facts are from the vendor pages; Sume facts from Verifying webhooks and Job webhooks, read 2026-10-01.
What did the Postgres minor release change?
The Supabase changelog covers PostgreSQL 15.19 and 17.11, available from September 28 and fixing 44 CVEs. Its breaking changes are ltree index corruption, a pgcrypto legacy-cipher change, a btree_gist NaN float change and restrictions on custom operator estimators. For pgcrypto it names blowfish, cast5 and bf, where decryption now fails by default.
| Area | Change |
|---|---|
| ltree | Index corruption fix |
| pgcrypto | Legacy ciphers (blowfish, cast5, bf): decryption fails by default |
| btree_gist | NaN float handling |
| Custom operators | Estimator restrictions |
What signature does Sume send?
HMAC-SHA256 over <timestamp>.<raw_body>, sent as x-sume-webhook-signature: sume-v1=<hex> with x-sume-webhook-timestamp. During a secret rotation there are comma-separated entries for 24 hours and any match is accepted. The default replay window is 300 seconds. PostgreSQL's pgcrypto has hmac(data text, key text, type text) returning bytea, and encode(..., 'hex') gives hex.
What does the function look like?
I ran this on Postgres 17 with pgcrypto installed in the extensions schema, as on Supabase; qualify hmac to match your schema. It returns false on an empty secret, a bad timestamp, a stale one or a mismatch, and handles two entries. It must be stable because it reads now(). The = comparison is not constant-time, which matters little over an HMAC but is why the SDK verifier is preferable where you can use it.
create or replace function public.verify_sume_webhook(
body text, ts text, sig_header text, secret text
) returns boolean
language plpgsql stable as $$
declare
entry text;
expected text;
begin
if secret is null or secret = '' or ts is null or sig_header is null
or ts !~ '^[0-9]{1,12}$' then
return false;
end if;
if abs(extract(epoch from now()) - ts::bigint) > 300 then
return false;
end if;
expected := 'sume-v1=' || encode(
extensions.hmac(ts || '.' || body, secret, 'sha256'), 'hex');
foreach entry in array string_to_array(replace(sig_header, ' ', ''), ',') loop
if entry = expected then
return true;
end if;
end loop;
return false;
end
$$;Where would you call it?
From a function that receives the raw body unparsed, passing the secret from its environment, not from a table you log. Do not parse and re-serialize the JSON first. For the usual route see the Supabase middleware post.
Does the upgrade need other checks?
Run a signed test with POST /v1/webhooks/test-deliveries after the upgrade, and keep status polling as a backup, since the docs call delivery a convenience.
Sources
Related posts
More in Developers
- Punch-in zoom on video by API: crop or zoompan, no keyframes
Sume has no auto zoom switch. Use a crop op for a fixed punch-in or the allowlisted zoompan filter in a video-filter graph; there are no keyframes.
- remove.bg API rate limit: 500 per minute, weighted by megapixels
remove.bg allows 500 images per minute at about 1 MP, less for larger inputs. Sume limits requests per minute per key and sends retry-after on 429.
- remove.bg bg_color replacement: Sume RMBG gives a transparent PNG
remove.bg's API has bg_color and bg_image_url. Sume RMBG 1.0 takes only an image_url and returns a PNG with alpha, so the new background is a second step.
- remove.bg crop and roi parameters: what Sume RMBG does instead
remove.bg has crop, roi, crop_margin, scale and position. Sume RMBG takes an image_url only and rejects other fields, so cropping happens before or after.
Written by Sume