Sume webhook rotation: upgrade the verifier before you click Rotate

During a rotation window Sume sends two signatures in one header. A receiver that compares the whole header for equality fails every delivery. Fix it first.

4 min readSume
All posts

The Sume SDK docs carry a caution before the rotation steps: upgrade the receiver before you rotate. For 24 hours after a rotation, x-sume-webhook-signature holds two entries, sume-v1=<new>,sume-v1=<old>, newest first. A hand-rolled verifier that compares the header with == fails every delivery during that window.

Outside a window the header has a single entry, so the bug stays invisible until the day you rotate.

Naive versus safe

Run the sample: both verifiers agree outside a window, and only the safe one survives inside it.

import hashlib, hmac, time

def sign(secret, ts, body):
    return hmac.new(secret.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()

def naive_ok(header, secret, ts, body):   # breaks while a rotation window is open
    return header == f"sume-v1={sign(secret, ts, body)}"

def rotation_safe_ok(header, secret, ts, body):
    want = sign(secret, ts, body)
    return any(hmac.compare_digest(p.removeprefix("sume-v1="), want) for p in header.split(","))

ts, body = str(int(time.time())), b'{"event":"job.completed"}'
single = f"sume-v1={sign('new', ts, body)}"
double = f"sume-v1={sign('new', ts, body)},sume-v1={sign('old', ts, body)}"
for label, header in (("outside a window", single), ("inside the 24 h window", double)):
    print(label, "naive:", naive_ok(header, "new", ts, body),
          "safe:", rotation_safe_ok(header, "new", ts, body))

Checklist before rotating

From the Sume SDK webhook docs, read 2026-10-06
CheckWhy
Verifier accepts any sume-v1 entryHeader has two entries during the window
Secret read from SUME_COM_WEBHOOK_SIGNING_SECRETOne place to change
Empty secret refusedFail closed rather than accept everything
Raw body is verifiedA re-serialized body changes the signature

Notes

  • verifyWebhook in @sume-com/sdk 0.2.0 already handles the multi-signature header and returns false rather than throwing.
  • Rotation needs account:write; rotation.previous_valid_until shows the end of the window.
  • Deploy the new secret to receivers during the window, not at the same instant you press the button.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume