T09 · Insecure Skill Coding Practices
- Location
SKILL.md:416- Finding
Malformed Webhook Signatures Can Trigger Unhandled Exceptions
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 416-425
Vulnerability Type: Improper input validation in webhook signature verification
Risk Level: LowVulnerable Code
javascript 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
The documented verification function passes the attacker-controlled
signaturevalue directly toBuffer.from()and then tocrypto.timingSafeEqual()without validating its presence, type, format, or length.Node.js requires both buffers passed to
crypto.timingSafeEqual()to have the same byte length. A missing, truncated, oversized, or otherwise malformedX-Claw-Signaturevalue can therefore cause an exception rather than returning a normal authentication failure. Depending on the surrounding webhook handler, this exception may produce repeated HTTP 500 responses or disrupt request processing.The function should also explicitly require the documented
sha256=prefix followed by exactly 64 hexadecimal characters and should calculate the HMAC over the exact raw request-body bytes.Attack Path
- An attacker identifies the application's publicly accessible Clawver webhook endpoint.
- The attacker submits a request with an absent or malformed
X-Claw-Signature, such as a signature with an incorrect length. - The application invokes the documented
verifyWebhook()function. Buffer.from(signature)andBuffer.from(expected)produce buffers of unequal lengths, or signature conversion itself fails for an invalid value.crypto.timingSafeEqual()throws an exception.- If the integrating request handler does not catch the exception, webhook processing fails. Repeated malformed requests may degrade endpoint availability or generate excessive errors.
I
...[truncated 432 chars]
- Remediation
View remediation
Remediation Suggestions
Validate the signature before performing the constant-time comparison:
- Require
signatureto be a string. - Enforce the exact format
sha256=followed by 64 hexadecimal characters. - Compare buffers only after confirming that their lengths are equal.
- Return
falsefor every malformed input instead of allowing an exception to escape. - Compute the HMAC over the exact raw request body, before JSON parsing or other transformations.
- Catch verification errors at the webhook-handler boundary.
- Apply request-size limits and rate limiting to the public webhook endpoint.
Example hardened implementation:
javascript const crypto = require('crypto'); function verifyWebhook(rawBody, signature, secret) { if ( typeof signature !== 'string' || !/^sha256=[0-9a-f]{64}$/i.test(signature) ) { return false; } const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); const suppliedBuffer = Buffer.from(signature, 'utf8'); const expectedBuffer = Buffer.from(expected, 'utf8'); if (suppliedBuffer.length !== expectedBuffer.length) { return false; } try { return crypto.timingSafeEqual(suppliedBuffer, expectedBuffer); } catch { return false; } }- Require
