All articles

Inngest Webhook Auth: When `event.key` Isn't Enough

Inngest Webhook Auth: When `event.key` Isn't Enough

Inngest signed webhooks are great — if you verify them. Vibe-coded handlers often trust the `event.key` field without checking the signature, and the whole workflow becomes callable by anyone.

May 9, 2026VibeWShield Team1 min read

Inngest gives you a reliable event/function model with automatic retries. It also requires you to verify the X-Inngest-Signature header on incoming webhook requests, and the AI scaffold routinely skips that step.

Vulnerable pattern

export const POST = async (req: Request) => {
  const body = await req.json();
  if (body.event.key !== "user/signup") return;
  await grantWelcomeBonus(body.event.data.userId);
  return Response.json({ ok: true });
};

An attacker pings this with {"event": {"key": "user/signup", "data": {"userId": "<any>"}}} and every user becomes "welcome bonus" forever.

Correct pattern

Use the Inngest SDK handler:

import { serve } from "inngest/next";
import { inngest } from "@/inngest/client";
 
export const { GET, POST, PUT } = serve({
  client: inngest,
  functions: [welcomeBonus, /*...*/],
});

The SDK verifies the signature for you. If you hand-write the handler, verify:

import crypto from "crypto";
 
const sig = req.headers.get("x-inngest-signature");
const body = await req.text();
const expected = crypto
  .createHmac("sha256", process.env.INNGEST_SIGNING_KEY!)
  .update(body)
  .digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(sig ?? ""), Buffer.from(expected))) {
  return new Response("bad signature", { status: 401 });
}

Bonus: idempotency

Even with signatures, retries happen. Always key your side effects (like granting a bonus) by event.id and store a processed-events log with a unique index. Two retries = one bonus.

Free security scan

Test your app for these vulnerabilities

VibeWShield automatically scans for everything covered in this article and more — 18 security checks in under 3 minutes.

Scan your app free