Fix Insecure Webhooks in SvelteKit
Webhooks are a high-value target for SSRF, replay attacks, and unauthorized state manipulation. In SvelteKit, exposing an API route in `+server.js` that processes external data without cryptographic verification is a critical vulnerability. If you're blindly parsing `request.json()` and updating your database, you've essentially built a public 'execute' button for your internal logic. Secure webhooks require raw body verification against a shared secret using HMAC.
The Vulnerable Pattern
export async function POST({ request }) { // VULNERABLE: No signature verification. Anyone can spoof this request. const payload = await request.json();if (payload.event === ‘payment.succeeded’) { await db.user.update(payload.userId, { premium: true }); }
return new Response(‘OK’); }
The Secure Implementation
To secure SvelteKit webhooks, you must implement three layers of defense: 1. Raw Body Access: Always use `request.text()` instead of `request.json()`. Re-stringifying a JSON object often results in different whitespace/key-ordering, which invalidates the HMAC. 2. HMAC Verification: Compute a SHA-256 hash of the raw body using a secret key stored in `$env/static/private`. 3. Constant-Time Comparison: Use `crypto.timingSafeEqual` to compare the provided signature with your calculated hash. This prevents attackers from brute-forcing the signature byte-by-byte by measuring response times.
import crypto from 'crypto'; import { WEBHOOK_SECRET } from '$env/static/private'; import { error } from '@sveltejs/kit';export async function POST({ request }) { const signature = request.headers.get(‘x-webhook-signature’); if (!signature) throw error(401, ‘Missing signature’);
// Use text() to get the raw body; json() can alter formatting and break the hash const body = await request.text();
const hmac = crypto.createHmac(‘sha256’, WEBHOOK_SECRET); const expectedSignature = hmac.update(body).digest(‘hex’);
// Use timingSafeEqual to prevent timing attacks const isValid = crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) );
if (!isValid) throw error(403, ‘Invalid signature’);
const payload = JSON.parse(body); // Logic only executes if the payload is authentic return new Response(‘Success’); }
Your SvelteKit API
might be exposed to Insecure Webhooks
74% of SvelteKit apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.