Optional inbound webhook HMAC signature verification #67
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Post-1.0 hardening (surfaced during the 1.0 review, see #33 — not a 1.0 blocker).
The receiver (
internal/handlers/webhook.go) does not verify sender authenticity. Many webhook senders sign payloads (e.g. GitHub-style HMAC-SHA256 over the body with a shared secret). Supporting optional verification lets operators reject spoofed events.Definition of done:
Reclassified to the
1.0.0milestone. The body above still says "not a 1.0 blocker" — that is superseded.The 2026-08-20 deployability audit established there is no inbound authentication of ANY kind:
internal/server/routes.go:219-224mounts/webhook/{uuid}behindReceiverRateLimit()alone, theEntrypointmodel has no secret column, and a grep forhmac|signature|x-hub-signature|stripe-signatureacrossinternal/returns zero non-comment hits. The only thing protecting an entrypoint is the secrecy of a v4 UUID in a URL path.Two things make that worse than "unauthenticated but obscure". Inbound headers are forwarded almost verbatim to the target (
internal/delivery/target_http.go:443-491strips only hop-by-hop plusProxy-Authorization), so anyone who learns the URL also chooses the headers the downstream service receives. And "durably stored" is the product's core claim, which is worth much less when provenance is unknown.Scope unchanged from the definition of done above, with one addition: the per-entrypoint secret must be settable and rotatable from the UI, and support at least the GitHub
X-Hub-Signature-256and GitLabX-Gitlab-Tokenshapes, since those are the senders that make the feature necessary. Rejection happens before persistence.clawbot referenced this issue2026-08-20 05:56:52 +02:00
Reversed and removed by #279, landed on
next.Owner's decision, 2026-08-24: "remove all the inbound request signing crap. the uuid url is the authentication secret." The entrypoint URL is a capability — possession of the UUID authorises submission, and that is the whole model.
The implementation this issue asked for is gone:
internal/signaturedeleted, the model fields and forms removed, the receiver verifying nothing inbound. Independent review confirmed no neighbouring receiver guard was weakened — the 1 MB cap, per-IP rate limiting, the 404/410 lookup and the cross-origin redirect header protection are all intact and were re-proven on a live instance.Closing.