GuardAPI Logo
GuardAPI

Fix Insecure Webhooks in Dropwizard

Insecure webhooks in Dropwizard applications are a prime target for SSRF and unauthorized state changes. If you process incoming POST requests without verifying the sender's identity via cryptographic signatures, an attacker can spoof events to trigger internal business logic. The goal is to enforce HMAC SHA-256 signature verification on every incoming webhook payload.

The Vulnerable Pattern

@POST
@Path("/events")
@Consumes(MediaType.APPLICATION_JSON)
public Response handleWebhook(EventPayload payload) {
    // VULNERABILITY: No signature verification.
    // Anyone can POST to this endpoint and trigger internal logic.
    db.updateStatus(payload.getId(), payload.getStatus());
    return Response.ok().build();
}

The Secure Implementation

The secure implementation shifts from automatic JSON binding to manual verification. First, it extracts the raw request body as a String to ensure the signature is calculated against the exact bytes received. It uses a shared secret to compute a local HMAC SHA-256 hash. Crucially, it utilizes 'MessageDigest.isEqual()' for a constant-time comparison, which mitigates timing attacks that could otherwise leak the signature byte-by-byte. Only after the signature is validated is the payload deserialized and processed.

@POST
@Path("/events")
public Response handleSecureWebhook(
    @HeaderParam("X-Webhook-Signature") String signature,
    String rawPayload) throws Exception {
String secret = configuration.getWebhookSecret();

// 1. Recompute the HMAC SHA-256 signature using the raw body
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmac.init(secretKey);
byte[] hash = hmac.doFinal(rawPayload.getBytes(StandardCharsets.UTF_8));
String expectedSignature = Base64.getEncoder().encodeToString(hash);

// 2. Timing-safe comparison to prevent side-channel attacks
if (signature == null || !MessageDigest.isEqual(signature.getBytes(), expectedSignature.getBytes())) {
    throw new WebApplicationException("Invalid Signature", Status.UNAUTHORIZED);
}

// 3. Manually deserialize after validation
EventPayload payload = objectMapper.readValue(rawPayload, EventPayload.class);
db.updateStatus(payload.getId(), payload.getStatus());
return Response.ok().build();

}

System Alert • ID: 1505
Target: Dropwizard API
Potential Vulnerability

Your Dropwizard API might be exposed to Insecure Webhooks

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