T09 · Insecure Skill Coding Practices
- Location
SKILL.md:157- Finding
Malformed Webhook Signatures Can Trigger Unhandled Exceptions
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 157–165
Vulnerability Type: Improper input validation in webhook signature verification
Risk Level: Mediumjavascript function verifyWebhook(body, signature, secret) { const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(body) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); }Technical Analysis
Node.js
crypto.timingSafeEqualrequires its two buffer arguments to have identical lengths. If the attacker-controlledX-Claw-Signatureheader is missing, truncated, oversized, or otherwise malformed,Buffer.from(signature)orcrypto.timingSafeEqualcan throw an exception rather than returningfalse.The example performs no presence, type, format, or length validation before comparing the supplied signature. If an application adopts this example without exception handling at the request boundary, malformed webhook requests can interrupt request processing and potentially affect process availability.
Attack Path
- An attacker locates the publicly reachable webhook endpoint.
- The attacker submits a request with a missing or malformed
X-Claw-Signature, such as a signature whose length differs from the expectedsha256=-prefixed hexadecimal digest. - The webhook handler passes the attacker-controlled value to
verifyWebhook. - Buffer creation or
crypto.timingSafeEqualthrows an exception because the input is invalid or the buffer lengths differ. - If the surrounding handler does not safely catch the exception, the request fails and may produce repeated errors or terminate the process in deployments configured to exit on uncaught exceptions.
- Repeated malformed requests can therefore degrade or deny webhook processing.
Impact Assessment
Exploitation does not grant access to the API key, webhook secret, customer ...[truncated 436 chars]
- Remediation
View remediation
Remediation Suggestions
Validate the signature header before constructing buffers and compare only equal-length values. The verifier should fail closed by returning
falsefor every malformed input rather than throwing.Recommended hardening measures:
- Require
bodyto be the exact raw request body used by the sender when computing the HMAC. - Verify that the signature exists and is a string.
- Require the exact
sha256=prefix and a 64-character hexadecimal digest. - Decode the received and expected digests explicitly as hexadecimal buffers.
- Check buffer lengths before calling
crypto.timingSafeEqual. - Catch verification errors at the HTTP request boundary and return a generic
401or400response. - Apply request-size limits, rate limiting, and security-conscious logging to the webhook endpoint.
Example hardened implementation:
javascript const crypto = require('crypto'); function verifyWebhook(body, signature, secret) { if ( !Buffer.isBuffer(body) || typeof signature !== 'string' || typeof secret !== 'string' ) { return false; } const match = /^sha256=([a-fA-F0-9]{64})$/.exec(signature); if (!match) { return false; } const received = Buffer.from(match[1], 'hex'); const expected = crypto .createHmac('sha256', secret) .update(body) .digest(); if (received.length !== expected.length) { return false; } return crypto.timingSafeEqual(received, expected); }The webhook route should additionally wrap verification in safe error handling so that unexpected runtime failures result in rejection rather than process disruption.
- Require
