A payment-provider event larger than 64 KB is cut off, fails its signature check and never reaches the console #146

Open
opened 2026-09-27 23:30:59 +00:00 by cgalo5758 · 1 comment
Owner

What happens

The Stripe webhook handler reads at most 65536 bytes of the request (const maxBodyBytes = 65536, read through io.ReadAll(io.LimitReader(r.Body, maxBodyBytes))). A larger body is cut off without an error. The shortened bytes fail signature verification, so the handler answers 400 and stores nothing. The log line says invalid Stripe webhook signature, which points at the signing secret, not at the size. Stripe retries the event with the same result until it stops retrying, and the console never learns of it. An invoice with many lines can go over 64 KB.

What should happen

An event up to the server's own 1 MB request cap is stored and its workflow started like any other. A body over the handler's limit is detected rather than cut off, answered 413, and logged with its size, never reported as a bad signature.

Where

internal/integrations/stripe/web/webhook.go (ServeHTTP, the body read). The server-wide cap is middleware.MaxBodySize(1024*1024) in internal/server/server.go; the Discourse receiver reads up to 256 KB.

Done when

  • A test sends a correctly signed event over 64 KB and gets 2xx; the event is stored and its workflow started.
  • A test sends a body over the handler's limit and gets 413, with a log line that gives the size.
## What happens The Stripe webhook handler reads at most 65536 bytes of the request (`const maxBodyBytes = 65536`, read through `io.ReadAll(io.LimitReader(r.Body, maxBodyBytes))`). A larger body is cut off without an error. The shortened bytes fail signature verification, so the handler answers 400 and stores nothing. The log line says `invalid Stripe webhook signature`, which points at the signing secret, not at the size. Stripe retries the event with the same result until it stops retrying, and the console never learns of it. An invoice with many lines can go over 64 KB. ## What should happen An event up to the server's own 1 MB request cap is stored and its workflow started like any other. A body over the handler's limit is detected rather than cut off, answered 413, and logged with its size, never reported as a bad signature. ## Where `internal/integrations/stripe/web/webhook.go` (`ServeHTTP`, the body read). The server-wide cap is `middleware.MaxBodySize(1024*1024)` in `internal/server/server.go`; the Discourse receiver reads up to 256 KB. ## Done when - A test sends a correctly signed event over 64 KB and gets 2xx; the event is stored and its workflow started. - A test sends a body over the handler's limit and gets 413, with a log line that gives the size.
cgalo5758 added the
kind
bug
area/billingarea/integrations
labels 2026-09-27 23:30:59 +00:00
Author
Owner

The Discourse receiver (internal/integrations/discourse/web/webhook.go) truncates the same way: it reads at most 256 KB through io.LimitReader, so a larger body fails its signature check, is answered 403 and logged as an invalid or missing signature. The fix should cover both receivers.

The Discourse receiver (`internal/integrations/discourse/web/webhook.go`) truncates the same way: it reads at most 256 KB through `io.LimitReader`, so a larger body fails its signature check, is answered 403 and logged as an invalid or missing signature. The fix should cover both receivers.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wiki-cafe/member-console#146