GuardAPI Logo
GuardAPI
Automated Security Protocol

How to fix Insecure Webhooks
in Poem

Executive Summary

Insecure webhooks in Poem are a critical vulnerability. Without cryptographic verification, an attacker can spoof events to trigger unauthorized actions, bypass business logic, or inject malicious data. Relying on IP whitelisting is a rookie mistake; you must implement HMAC signature verification to ensure the payload originated from a trusted source and wasn't tampered with in transit.

The Vulnerable Pattern

VULNERABLE CODE
use poem::{post, handler, web::Json, Route, Server, endpoint::make_sync};

#[handler] async fn insecure_webhook(payload: Json<serde_json::Value>) -> String { // VULNERABLE: The handler trusts any POST request to this endpoint. // An attacker can send a fake ‘order_paid’ event to unlock premium features. println!(“Processing event: {:?}”, payload); “Event Processed”.to_string() }

fn main() { let app = Route::new().at(“/webhook”, post(insecure_webhook)); }

The Secure Implementation

The secure implementation utilizes HMAC-SHA256 to validate the payload's integrity and authenticity. Key security controls implemented: 1. Raw Body Access: We extract the raw bytes from the request body before any JSON deserialization occurs, ensuring the signature is checked against the exact data sent. 2. Shared Secret: A high-entropy secret known only to the provider and the application is used. 3. Constant-Time Comparison: The 'verify_slice' method from the hmac crate is used to prevent timing attacks that could leak the signature. 4. Header Validation: The request is immediately rejected with a 401 Unauthorized if the signature header is missing or invalid.

SECURE CODE
use poem::{handler, post, web::Data, Request, Body, Route, http::StatusCode, Result};
use hmac::{Hmac, Mac};
use sha2::Sha256;
use hex;

type HmacSha256 = Hmac;

#[handler] async fn secure_webhook(req: &Request, mut body: Body) -> Result { let secret = std::env::var(“WEBHOOK_SECRET”).expect(“SECRET NOT SET”);

// 1. Extract the signature header
let signature_header = req.headers()
    .get("X-Hub-Signature-256")
    .and_then(|v| v.to_str().ok())
    .ok_or(StatusCode::UNAUTHORIZED)?;

// 2. Read the raw body bytes (crucial: do not parse JSON before verification)
let body_bytes = body.into_bytes().await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

// 3. Compute HMAC-SHA256
let mut mac = HmacSha256::new_from_slice(secret.as_bytes())
    .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
mac.update(&body_bytes);

// 4. Constant-time verification
let expected_sig = hex::decode(signature_header.replace("sha256=", ""))
    .map_err(|_| StatusCode::BAD_REQUEST)?;

mac.verify_slice(&expected_sig)
    .map_err(|_| StatusCode::UNAUTHORIZED)?;

// Now it is safe to parse and process the payload
Ok("Verified and Processed".to_string())

}

System Alert • ID: 4808
Target: Poem API
Potential Vulnerability

Your Poem API might be exposed to Insecure Webhooks

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