1
0

fix(server): verify Plaid webhook signatures (GHSA-g56w-g54f-whq5)

POST /api/banking/plaid/webhooks was @PublicRoute() and processed the
body without verifying Plaid's Plaid-Verification JWT, letting any
unauthenticated client replay or fabricate webhook events for a tenant
by guessing a plaidItemId.

Add PlaidWebhookVerificationService that verifies the Plaid-Verification
ES256 JWS using a JWK fetched from plaidClient.webhookVerificationKeyGet
(cached per kid via lru-cache for 24h), enforces a 5-minute iat replay
window through jose.jwtVerify({ maxTokenAge }), and timing-safe compares
the body's SHA-256 against the request_body_sha256 claim. The webhook
controller now consumes the raw body and the plaid-verification header,
runs verification before setupPlaidTenant, and returns 400 Bad Request
on any failure - so no tenant context is ever set for an unsigned or
tampered request.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ahmed Bouhuolia
2026-05-16 12:19:30 +02:00
parent cd8d10afc0
commit 78fb158b98
5 changed files with 378 additions and 249 deletions
+243 -237
View File
File diff suppressed because it is too large Load Diff