Skip to content

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

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 expected_signature not in signatures:
+ expected = expected_signature.encode()
+ if not any(hmac.compare_digest(expected, signature.encode()) for signature in signatures):

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. Bytes, because compare_digest raises TypeError on non-ASCII strings.

🤖 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

🧪 Test coverage

Metric Value
Endpoints reached (HTTP) 120 / 120 (100.0%)

✅ Every endpoint operation was reached by a real request.

Endpoint reach is measured from HTTP requests actually sent by the suite (see tests/utils/client.py). See TESTING.md.

@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

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

Non-ASCII signatures raise an unexpected TypeError and prevent later valid signatures from matching.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Hardens webhook verification against timing leaks while preserving support for rotated signatures.

Changes:

  • Uses hmac.compare_digest for signature comparisons.
  • Adds tests for a later valid signature and a near-match rejection.
File Description
tests/​test_webhooks.py Adds signature acceptance and rejection tests.
src/​gr4vy/​webhooks.py Replaces membership checking with constant-time comparisons.

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

Comment thread src/gr4vy/webhooks.py Outdated
hmac.compare_digest raises TypeError on non-ASCII strings, so a header
containing one skipped the ValueError path and any valid signature after it.
Compare bytes instead.

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

Copilot AI left a comment

Copy link
Copy Markdown

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 focused change preserves existing behavior, resolves the prior non-ASCII issue, and includes regression coverage.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@cbetta
cbetta merged commit 648aa7a 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