~/work/hookferret.md
Back to workHookFerret
A self-hosted, throwaway webhook inbox — capture any webhook to a disposable URL, inspect it live, and see how it's signed so you can verify it, in-browser.
Founder & Engineer · 2026
HookFerret is a throwaway webhook inbox that captures any request, shows it to you live, and works out exactly how the provider signed it — without a single byte of secret leaving your browser.
The problem
Wiring up a webhook integration is painful in three ways. You need a public URL to receive the events, a live view of the raw method, headers, and body while you build, and — the hard part — a way to work out how the provider signed the payload: which HMAC algorithm, which digest encoding, and exactly which bytes were signed, so you can verify signatures in your own code.
Hosted inbox tools solve the first two, but they ask you to trust a third party with payloads that carry auth headers and PII — and none of them will work out a signing scheme for you. HookFerret is self-hosted, retains nothing, keeps signing secrets on your machine, and resolves the signature scheme client-side.
What I built
- Ephemeral webhook inboxes — mint a unique ingest URL with one click and point any HTTP sender at it. Every request is captured byte-for-byte and streams into the dashboard live, while inboxes and requests auto-expire on a short TTL (with sliding renewal for an active inbox), so nothing sticks around.
- A live dark inspector — each captured request shows its method, path, source IP, content-type, size, every header, and the raw body decoded exactly as sent (with binary detection). A Copy as cURL button reconstructs the exact request to replay from a terminal.
- A client-side signature-scheme solver — the standout feature. For every signature-looking header, HookFerret tests a full matrix — HMAC vs. plain hash × SHA-1/256/512 × hex/base64/base64url × six signed-input shapes × five key encodings — entirely in the browser, and reports every combination that reproduces the header. It’s provider-agnostic and needs zero per-provider setup.
- Provider-style hints — a matched scheme is labeled GitHub-style, Stripe-style, Slack-style,
Shopify-style, or Svix / Standard-Webhooks-style, framed honestly as a resemblance since real
schemes overlap. HookFerret also auto-detects the signature header, the signed timestamp
(from a dedicated header or Stripe’s embedded
t=), and the Svix message id. - Secrets that never leave the tab — signing secrets are pasted into the dashboard, kept in that one browser tab, and are never sent to the server, logged, or stored. There is deliberately no server-side detection endpoint; the signature-scheme solving runs on the Web Crypto API.
- Serverless by construction — the whole app runs on AWS Lambda behind a throttled HTTP API, with DynamoDB TTL as the expiry engine and large bodies overflowing to KMS-encrypted S3. It scales to zero when idle, so idle cost is near nothing.
- Runs anywhere —
npm run dev(ordocker compose up) boots a zero-dependency Node server backed by an in-memory store whose routes mirror the production Lambdas, plus a seed script that fires correctly-signed sample webhooks (GitHub, Stripe, Shopify, Slack) so capture and detection light up instantly for a demo.
How it’s built
The backend is a hexagonal split so the same core logic runs locally and on Lambda behind a swappable storage interface. Pure, cloud-agnostic capture and inbox logic lives in a core layer that never sees a signing secret; a Store contract has two implementations — an in-memory store for local dev and tests, and a DynamoDB-plus-S3 store for AWS — selected at runtime. The Lambda handlers are thin adapters over API Gateway’s HTTP API v2 events, and a plain Node dev server re-implements the same route table so local behavior matches production. Request bodies are stored and returned as raw bytes, never JSON round-tripped, so HMAC verification stays exact.
The entire cloud stack is one AWS SAM / CloudFormation template: a single-table DynamoDB
design with per-item TTL, a locked-down KMS-encrypted S3 bucket for overflow bodies, six arm64
Node 22 Lambdas, a throttled HTTP API, and optional custom-domain and cost-guardrail resources
gated behind stack parameters. The dashboard is a hand-authored, buildless vanilla-JS SPA served
under a strict Content-Security-Policy — no inline scripts, no innerHTML, everything same-origin —
with real accessibility work: a keyboard-navigable request list and live-region announcements of new
captures. The signature engine is a single pure Web Crypto module written to run identically in
the browser and under Node, so it is unit-tested directly. A CI gate (audit → format → lint → types →
test → build → end-to-end verify) and keyless GitHub Actions deploys via OIDC keep it honest.
[0]