Skip to content

fix(webhooks): compare signatures in constant time - #328

Merged
cbetta merged 2 commits into
mainfrom
fix/constant-time-webhook-signatures
Oct 2, 2026
Merged

cbetta merged 2 commits into
mainfrom
fix/constant-time-webhook-signatures

Conversation

@cbetta

@cbetta cbetta commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Compares webhook signatures in constant time.

- if(!signatures.contains(expectedSignature)) {
+ boolean matched = signatures.stream()
+     .anyMatch(signature -> MessageDigest.isEqual(expected, signature.getBytes(UTF_8)));
+ if(!matched) {

The old comparison stops at the first character that differs, so how long a rejection takes shows how much of a guessed signature was right. Rotation still works: any one of the comma-separated signatures can match. The expected signature goes first because isEqual's time follows its first argument's length.

🤖 Generated with Claude Code

The old comparison stopped at the first character that differed, so how long
a rejection took showed how much of a guessed signature was right.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Endpoint-reach coverage

120 / 120 operations reached by a real HTTP request (100%).

Every operation in the SDK was reached. 🎉

@cbetta
cbetta marked this pull request as ready for review October 2, 2026 15:48
Copilot AI balanced review requested due to automatic review settings October 2, 2026 15:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The timing-safe comparison operands must be reversed so execution time depends on the fixed expected digest length.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Updates webhook signature verification to use timing-safe comparisons while preserving signature rotation support.

Changes:

  • Uses MessageDigest.isEqual for signature checks.
  • Adds valid-position and near-match tests.
File Description
src/​main/​java/​com/​gr4vy/​sdk/​Webhooks.java Adds timing-safe signature comparison.
src/​test/​java/​com/​gr4vy/​sdk/​WebhooksTest.java Adds signature verification coverage.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/main/java/com/gr4vy/sdk/Webhooks.java Outdated
MessageDigest.isEqual takes time in proportion to its first argument, which
was the signature from the header. Put the fixed-length expected one first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The security fix is correctly implemented and adequately covered by focused tests.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@cbetta
cbetta merged commit 526b5b5 into main Oct 2, 2026
14 checks passed
@cbetta
cbetta deleted the fix/constant-time-webhook-signatures branch October 2, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants