hookwarden documentation
hookwarden finds the webhook handlers in your codebase and checks that each one verifies the provider's signature before it trusts the payload. It runs on your machine, makes no network calls, and gives every finding a file, a line, and a fix.
Install
Run it with no install at all, or add it natively through your OS package manager.
Requires Node 22+ for the npm / npx path. JavaScript, TypeScript, Python 3.10+, PHP 8.0+, and Go 1.21+ are scanned out of the box. Windows: scoop install hookwarden.
Quick start
Point scan at any app. Each finding carries a severity glyph, the exact file:line, the rule id, the three-state verdict, and a fix drawn verbatim from the provider's docs.
The exit code tells CI what happened. Set the threshold with --fail-on (default critical).
| 0 | No findings at or above the threshold. |
| 1 | At least one finding at or above the threshold. |
| 2 | The engine hit an error and the scan is incomplete. |
| 3 | The command line or config file is invalid. |
Three-state verdicts
Every handler gets one of three verdicts. Severity is separate: it ranks how bad a finding is, and it's what --fail-on compares against.
- verified
const event = stripe.webhooks.constructEvent(rawBody, sig, secret);A correct signature check runs before the handler uses the payload. Nothing to do.
- not-verified
const event = JSON.parse(req.body);The handler trusts the payload without a valid check: the signature is never verified, compared with ==, or computed over an already-parsed body. Fix it before you ship.
- manual-review
app.post("/webhooks/stripe", verifyFrom(config), handle);The source alone can't prove it safe or unsafe, for example when verification happens in middleware hookwarden couldn't follow. It doesn't fail CI by default; someone should take a look.
Fixing findings
hookwarden fix applies the mechanical remediations with a real AST-rewrite engine — === → crypto.timingSafeEqual, == → hash_equals, and so on. It's dry-run by default; pass --write to apply.
Read path and write path are separate by design — scan --fix is rejected at parse time. Only fixes the three-state engine classified as safe are auto-applied.
Continuous integration
Gate every pull request. The official GitHub Action runs the scan, fails the build at your severity threshold, and uploads SARIF to Code Scanning so findings appear as PR annotations.
Providers & frameworks
Each provider's rule pack encodes signature quirks a generic scanner can't know — Stripe's 5-minute timestamp tolerance, Slack's v0:${ts}:${body} scheme, Twilio's SHA1 outlier.
Providers
- Anthropic Agent SDK
- Auth0
- Bitbucket
- Calendly
- Discord
- DocuSign
- GitHub
- HubSpot
- Intercom
- Linear
- Mailchimp
- n8n
- Notion
- PagerDuty
- Postmark
- Sentry
- Shopify
- Slack
- Square
- Stripe
- Twilio
- Zendesk
- Zoom
- Standard Webhooks (Clerk, Resend, Svix and others)
Frameworks
| JavaScript, TypeScript | Express, Hono, Fastify, Next.js |
| Python | Flask, FastAPI, Django |
| PHP | Laravel, Symfony, Slim, plain PHP |
| Go | net/http, chi, gin, echo |
From CLI to platform
The CLI finds and fixes bugs on your machine. The hosted platform keeps watching after you ship: connect a repo and hookwarden scans every push, rotates webhook secrets without dropping a delivery, and keeps a tamper-evident record your auditor can read. Org-wide coverage runs through a read-only GitHub App.
The hosted platform is launching soon. Everything above this section works today with the free CLI.
Connect a repo
Install the hookwarden GitHub App and choose which repositories to watch. The App takes read-only access to source — it never needs write access to your code. From then on every push is scanned automatically; there's nothing to run.
Org-wide installs use a GitHub App (not an OAuth App) so coverage follows the org, not one person's token.
Continuous scanning
The same engine as the CLI, run on every push. The dashboard tracks your findings delta over time — new, persisting, and fixed — alongside a live inventory of every webhook handler across your connected repos, each labelled with its provider, framework, and verdict.
Automated rotation
Rotating a webhook secret is risky — swap it too early and you drop live deliveries. hookwarden opens a dual-secret window: both the old and new secret stay valid until a real webhook validates against the new one, then the old is retired. Every rotation requires your confirmation, and every step is signed into the audit log.
Fully automated rotation runs for Stripe and GitHub today. Every other provider is handled by a guided runbook — same dual-secret safety, same audit trail.
Rotation runbooks
Some providers expose no rotation API, and some have no overlap window at all. For those, hookwarden ships a guided runbook per provider: an ordered, gated checklist that walks you through the exact dashboard steps, verifies a live delivery against the new secret before you finish, and signs each step to the audit log — so a manual rotation is as auditable as an automated one.
Each runbook is labelled dual-secret or single-swap so you know whether there's an overlap window before you start.
Audit log & SOC2 evidence
Every scan, finding, and rotation step is appended to a hash-chained, tamper-evident log — each entry links to the one before it and the chain is KMS-signed, so a missing or altered row is detectable. It's the chain-of-custody an auditor asks for, not a dashboard screenshot.
Missing a provider or framework? Open an issue on GitHub.