WebhookEngine v0.1.5
WebhookEngine v0.1.5
Post-audit hardening release. A multi-agent deep audit covered security, memory, concurrency, code quality, frontend, operations, timezone correctness, and NuGet SDK compliance; the resulting fixes (F1–F10) plus an idempotency race fix (F7) and an SDK target-framework simplification all land here. No breaking API changes — the v1 route prefix and Standard Webhooks header names are preserved.
Features / Fixes / Changes
Added
- health probes:
/health/live(process up) and/health/ready(AppReadinessGate+DbContext.CanConnectAsync) for orchestrators (F5) - observability: OpenTelemetry tracing with optional OTLP export via
OpenTelemetry:OtlpEndpoint(F5) - sdk:
WebhookVerifierfor Standard Webhooks signature verification —FixedTimeEquals, 5-min default tolerance,whsec_/ base64 secrets, multi-value signatures (F9)
Changed
- sdk: target framework simplified from
net10.0;net9.0;net8.0tonet10.0only — pre-v1.0cleanup, NuGet badge flips to.NET 10.0 - memory:
IMemoryCachesize-bounded (SizeLimit = 10_000) with per-app cancellation-token-source invalidation (F4) - shutdown:
HostOptions.ShutdownTimeout = 45sso in-flight HTTP deliveries can drain on SIGTERM (F10) - security: dashboard admin default credentials rejected at startup outside Development (F5)
Fixed
- idempotency race: UNIQUE partial index on
(app_id, endpoint_id, idempotency_key)+ Stripe-style 23505-replay + retention NULL-out for window reuse (F7) - duplicate attempts on lock loss: CAS guards on
Mark{Delivered,FailedForRetry,DeadLetter}Asyncreturningbool(F2) - circuit-breaker race:
EndpointHealthTrackermutations serialized viapg_advisory_xact_locknamespace100_001(F3) - frontend:
webhookengine:auth-expiredCustomEventon 401 +RouteErrorBoundaryforChunkLoadErrorafter deploys (F8) - memory leaks:
HttpResponseMessagedisposal +EndpointRateLimiteridle-window eviction (15-minIdleAfter, 5-min sweep) (F9) - migration race: startup migration block wrapped in
pg_advisory_locknamespace200_000(F5)
Security
- SSRF + DNS rebinding:
PrivateIpDetectorblocks RFC1918/loopback/link-local/CGNAT/IPv6 unique-local;SocketsHttpHandler.ConnectCallbackpins resolved IP (F1) - headers + metrics gate: HSTS / CSP / X-Frame-Options DENY / X-Content-Type-Options / Referrer-Policy / Permissions-Policy;
/metricsBearer-token auth viaWebhookEngine:Metrics:ScrapeToken; cookieSecurePolicy = Alwaysoutside Dev/Testing (F6) - custom headers:
CustomHeaderPolicyrejects reserved headers (Authorization,Cookie,Host,Content-*,webhook-*), strips CR/LF, bounds size (F10)
Migration
One auto-applying migration ships in this release: 20260505140607_AddIdempotencyUniqueIndex. It NULL-outs any pre-existing duplicate (app_id, endpoint_id, idempotency_key) triples (keeping the most-recent row per group) before creating the unique index, so it cannot fail on legacy data.
Quick Start
docker pull voyvodka/webhook-engine:0.1.5
docker compose up