Skip to content

bug(sdk/ts): TypeScript verifyWebhook throws on truncated signatures #144

Description

@ron-42

Summary

verifyWebhook in @inkbox/sdk calls Node's timingSafeEqual with no length check. When X-Inkbox-Signature starts with sha256= but the hex digest is not exactly 64 characters, verification throws RangeError: Input buffers must have the same byte length instead of returning false.

Python (hmac.compare_digest) and Rust (explicit length guard) already return false for unequal lengths. The TypeScript path does not.

A webhook receiver that trusts verifyWebhook to return a boolean and does not wrap it in try/catch will 500 on malformed or attack traffic instead of rejecting with 403.

Reproduction

import { verifyWebhook } from "@inkbox/sdk";

verifyWebhook({
  payload: Buffer.from('{"event":"message.received"}'),
  headers: {
    "x-inkbox-signature": "sha256=abcd", // truncated
    "x-inkbox-request-id": "req-1",
    "x-inkbox-timestamp": "1741737600",
  },
  secret: "test-signing-key",
});
// throws RangeError — should return false

Same throw for sha256=, odd-length digests, and digests longer than 64 hex chars. Wrong digests of the correct length already return false correctly.

Evidence in tree

// sdk/typescript/src/signing_keys.ts
const expected = createHmac("sha256", key).update(message).digest("hex");
const received = signature.slice("sha256=".length);
return timingSafeEqual(Buffer.from(expected), Buffer.from(received));

Rust already documents the divergence:

// sdk/rust/src/signing_keys.rs
// Differing lengths short-circuit to `false`
// (compare_digest never raises here, unlike TS `timingSafeEqual`).
if expected_bytes.len() != received_bytes.len() {
    return Ok(false);
}

Existing TS tests only cover equal-length failures, so CI stays green.

Proposed fix

Guard length before timingSafeEqual and return false, matching Python/Rust. Add a regression test for a truncated sha256=… signature.

Impact

  • Security-adjacent: auth helper must not throw on attacker-controlled header lengths.
  • Affects any TS/CLI webhook receiver using verifyWebhook (including cli and examples that call the shared helper).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions