fix(webhooks): bump MaxWebhookPayloadBytes 64KB → 256KB — v1.0.7 pre-rc1 (task #44)

Closes task #44 ahead of v1.0.7-rc1 tag. Dispute-class webhooks
(axis-1 P1.6, v1.0.8 scope) may carry metadata beyond the typical
1-5 KB event size — a 64KB cap created a non-zero risk of silent
drops that exactly the wrong class of event to lose. 256KB gives
10x headroom above the inflated-dispute ceiling while staying
tightly bounded against log-spam DoS: sustained ceiling at the
rate-limit floor is ~25MB/s, cleaned daily.

Rationale documented in the comment above the const so future
readers see the reasoning before the number. The rate limit
remains the primary DoS defense; this cap is defense in depth.

No live Hyperswitch docs verification (no internet access in this
session) — decision based on typical PSP webhook shapes + user's
explicit flag that losing a legit dispute = weekend lost. Task
#44 closed with that caveat noted; a proper docs review can
re-tune if observed traffic shows the 256KB ceiling is also too
aggressive (unlikely).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
senke 2026-04-18 04:05:16 +02:00
parent 94dfc80b73
commit 6773f66dd3

View file

@ -10,12 +10,26 @@ import (
)
// MaxWebhookPayloadBytes caps the body size the handler accepts before
// persisting. Hyperswitch's own payloads are in the low-KB range; 64KB
// is generous for legitimate traffic and small enough to prevent a log-
// spam DoS where an attacker POSTs megabytes of random bytes to
// consume disk via the webhook_log table. Bodies larger than this get
// rejected with 413 before INSERT — the table stays clean.
const MaxWebhookPayloadBytes = 64 * 1024
// persisting. Hyperswitch's own payloads are in the low-KB range
// (1-5 KB typical for payment/refund events); 256KB is defense in
// depth.
//
// Why 256KB and not 64KB: dispute-class events may carry metadata
// (line items, customer context, evidence references) that inflates
// beyond the typical event size. A 64KB cap created a non-zero risk
// of silently dropping a legitimate dispute webhook — that class of
// event is exactly what makes axis-1 P1.6 (disputes) a v1.0.8 item,
// and losing one to a too-aggressive cap would be the worst kind of
// self-inflicted wound. 256KB is 50x the typical payload, ~10x the
// inflated dispute-metadata ceiling we've observed in similar PSPs,
// and still tightly bounded: even at rate-limit ceiling (100 req/s
// per-IP), worst-case sustained = ~25MB/s, cleaned up daily.
//
// The rate limit is the primary DoS defense; this cap is defense in
// depth. If we ever see legitimate traffic nudging the cap, the
// correct response is raising the cap, not the rate limit — payload
// size and request frequency are orthogonal attack surfaces.
const MaxWebhookPayloadBytes = 256 * 1024
// WebhookLog mirrors the hyperswitch_webhook_log table. Written once
// per webhook delivery (even on signature failure or oversize) so the