WebhookEngine v0.4.0
Reliability and security release. A full audit closed the delivery-correctness and API defects behind double delivery, silent message loss, and racy manual retries, alongside three security fixes and the operator backlog metrics an alert can actually fire on. No breaking API changes — the v1 prefix, the Standard Webhooks signature surface, and the WebhookEngine.Sdk public API are unchanged.
Security
- Authenticated SignalR delivery hub.
/hubs/deliverieswas mapped with no authorization while the notifier fans every delivery event toClients.All— any anonymous client that could reach the host received the system-wide delivery firehose for all applications, defeating the AppId isolation enforced everywhere else. The hub now requires the dashboard cookie scheme, with/negotiategated too. - IP allowlist enforced at connect time (DNS-rebinding hardening). The allowlist was checked in the worker against its own DNS resolution, but the delivery connection re-resolved the host and pinned to that result. Hostile DNS could return an allowlisted IP to the check and a different one to the connection. The connect callback now enforces the allowlist on the same resolution it pins to.
- Login rate limiting.
POST /api/v1/auth/loginhad no throttle, so seeded admin credentials could be brute-forced online. It now carries a fixed-window limiter (5 attempts/minute per client IP, configurable underWebhookEngine:LoginRateLimit). - Portal endpoint-test preview no longer leaks custom-header values. The portal test response redacts every operator-configured custom-header value while preserving the Standard Webhooks signed headers.
Fixes
- Delivery lifecycle hardened. Per-message CAS lock refresh stops
StaleLockRecoveryWorkerfrom reclaiming a message a live worker is still delivering; delivery now runs on a per-request timeout independent of shutdown so an in-flight message finalizes cleanly on SIGTERM; and error recovery is a CAS reset that can no longer regress aDelivered/DeadLetterrow back toPending. - A failed enqueue no longer silently drops a sibling message. A poisoned
DbContexton fan-out meant a later endpoint never received the webhook while the API still returned success. - Manual retry is race-safe, and a circuit-open endpoint no longer burns a message's retry budget into a premature dead-letter.
- List pagination is bounded across all 11 paginated routes (
?pageSize=2000000000could materialize an entire tenant'smessagestable), date filters accept naked dates, and thesecretOverridesigning-secret rule is enforced on every surface. - Dashboard live auto-refresh no longer freezes after the 20-event feed cap — the message table and 24-hour counters stayed frozen while the page still looked live.
- Query performance on the growth paths. New partial index for the retry sweep, an index for the timeline scan, and endpoint-stats p95 computed via
percentile_continstead of loading every attempt's latency into memory.
Features
- Operator backlog metrics. Three new Prometheus gauges —
webhookengine_queue_depth,webhookengine_queue_oldest_pending_age(head-of-line latency, the real SLO signal), andwebhookengine_circuit_open— refreshed by a background collector every 15s so the scrape path stays cheap. These replace a queue-depth up/down counter that drifted monotonically negative on every retry, making the documented backlog alert unfireable.
Upgrade notes
webhookengine_queue_depthchanges semantics from a drifting counter to a real gauge; existing alerts on it become meaningful rather than dead.- Endpoint-stats p95 is now a continuous-interpolated percentile (the standard definition) rather than a nearest-rank sample, so the value can differ slightly for identical data.
- Replaying a message now applies the currently configured
RetryPolicy:MaxRetriesrather than the original message's cap.
Quick Start
docker pull voyvodka/webhook-engine:0.4.0
docker compose up -dLinks
- Docker Hub: https://hub.docker.com/r/voyvodka/webhook-engine
- NuGet: https://www.nuget.org/packages/WebhookEngine.Sdk
- Documentation: https://webhook.sametozkan.com.tr
- Full changelog: https://github.com/voyvodka/webhook-engine/blob/main/CHANGELOG.md