GuardAPI Logo
GuardAPI
Automated Security Protocol

How to fix Insecure Webhooks
in Plug

Executive Summary

Webhooks are often the weakest link in an Elixir/Plug stack. If you aren't cryptographically verifying the payload origin, you're effectively exposing an unauthenticated RCE or state-manipulation endpoint. Attackers can spoof events, bypass business logic, and inject malicious data. Security in Plug requires capturing the raw request body and validating it against a shared secret using constant-time comparison.

The Vulnerable Pattern

VULNERABLE CODE
defmodule MyProjectWeb.WebhookController do
  use MyProjectWeb, :controller

def handle_webhook(conn, params) do # VULNERABLE: Implicitly trusts the parsed JSON body. # No signature verification occurs. case params[“type”] do “user.deleted” -> delete_user(params[“id”]) _ -> :ok end send_resp(conn, 200, "") end end

The Secure Implementation

1. Raw Body Integrity: Verification must be performed on the raw binary body before JSON parsing. Once parsed, key order or whitespace changes will invalidate the HMAC. 2. Constant-Time Comparison: Use `Plug.Crypto.secure_compare/2` to prevent timing attacks that leak the valid signature. 3. Shared Secret: Use a high-entropy secret stored in environment variables, never hardcoded. 4. Enforcement: Apply the verification Plug specifically to webhook routes to ensure every incoming request is authenticated via the HMAC signature.

SECURE CODE
defmodule MyProjectWeb.WebhookPlug do
  import Plug.Conn
  @webhook_secret "your_shared_secret_key"

def init(opts), do: opts

def call(conn, _opts) do with [signature] <- get_req_header(conn, “x-hub-signature-256”), {:ok, body, conn} <- read_body(conn), true <- verify_signature(body, signature) do assign(conn, :raw_body, body) else _ -> conn |> send_resp(401, “Unauthorized”) |> halt() end end

defp verify_signature(body, “sha256=” <> actual_sig) do expected_sig = :crypto.mac(:hmac, :sha256, @webhook_secret, body) |> Base.encode16(case: :lower) Plug.Crypto.secure_compare(expected_sig, actual_sig) end defp verify_signature(_, _), do: false end

System Alert • ID: 7016
Target: Plug API
Potential Vulnerability

Your Plug API might be exposed to Insecure Webhooks

74% of Plug 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.