GuardAPI Logo
GuardAPI

Fix Insecure Webhooks in Astro

Webhooks are your application's exposed nerves. In Astro, API routes acting as webhook consumers are often left wide open, trusting any POST request that hits the endpoint. Without cryptographic verification, an attacker can replay events, spoof payments, or trigger unauthorized state changes. To secure them, you must implement signature verification using a shared secret.

The Vulnerable Pattern

export const POST = async ({ request }) => {
  // VULNERABILITY: Trusting the body without verification
  const body = await request.json();

if (body.type === ‘payment.succeeded’) { await fulfillOrder(body.orderId); }

return new Response(JSON.stringify({ received: true }), { status: 200 }); };

The Secure Implementation

The secure implementation moves from implicit trust to zero-trust. Key improvements: 1. It extracts the raw request body as text before parsing, ensuring the HMAC hash matches exactly what the provider sent. 2. It generates a local SHA-256 HMAC using a protected environment variable. 3. It utilizes 'crypto.timingSafeEqual' to compare signatures, which prevents attackers from brute-forcing the hash via millisecond-level response time differences (timing attacks). If the signature fails, the process terminates before any business logic executes.

import crypto from 'node:crypto';

export const POST = async ({ request }) => { const signature = request.headers.get(‘x-webhook-signature’); const secret = process.env.WEBHOOK_SECRET;

if (!signature || !secret) { return new Response(‘Missing signature or secret’, { status: 401 }); }

// Use raw text for hash verification to avoid JSON parsing discrepancies const rawBody = await request.text(); const hmac = crypto.createHmac(‘sha256’, secret); const expectedSignature = hmac.update(rawBody).digest(‘hex’);

// Use timingSafeEqual to prevent timing attacks const isValid = crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) );

if (!isValid) { return new Response(‘Invalid signature’, { status: 401 }); }

const data = JSON.parse(rawBody); await fulfillOrder(data.orderId);

return new Response(‘Verified’, { status: 200 }); };

System Alert • ID: 5484
Target: Astro API
Potential Vulnerability

Your Astro API might be exposed to Insecure Webhooks

74% of Astro apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

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.