ZeroHour

CVE-2026-70658

moderate

Timing side-channel in Pay gem's Paddle Billing webhook signature check

CVSS 3.1
7.4 high
EPSS
Published
()
Modified
AI analysis

The Pay payments engine for Ruby on Rails, in versions prior to 11.6.2, verifies Paddle Billing webhook signatures by comparing the computed 64-character SHA-256 HMAC against the attacker-controlled h1 token from the Paddle-Signature header using Ruby's String#==, which is not constant-time. An unauthenticated remote attacker who can repeatedly submit requests to /pay/webhooks/paddle_billing and obtain sufficiently precise timing measurements can infer matching digest prefixes and gradually recover a valid signature. A forged, accepted webhook is then enqueued through Pay::Webhooks::ProcessJob and can drive the host application to update billing state, provision paid features, record refunds, or trigger customer notifications. Any Rails 6.0+ application using the pay gem below 11.6.2 with Paddle Billing webhook processing enabled is affected; the endpoint is unauthenticated and internet-reachable by design. CVSS 3.1 is 7.4 (high) with high attack complexity due to the timing precision required, and no public PoC or in-the-wild exploitation is currently known.

What to do: Upgrade the pay gem to version 11.6.2 or later, where the comparison is fixed, and redeploy. If immediate upgrade is not possible, apply compensating controls on /pay/webhooks/paddle_billing such as rate limiting, allowlisting Paddle's webhook source IP ranges, and alerting on bursts of failed-signature requests with varying h1 values. Audit processed Paddle Billing webhook events and billing-state changes (refunds, feature provisioning, notifications) for signs of forged submissions.

Affected
Pay (pay-rails) pay — payments engine for Ruby on Rails< 11.6.2 (fixed in 11.6.2)
Estimated exposure
moderatelikely low thousands of Rails applications (order of magnitude 1,000–10,000), each internet-exposed at /pay/webhooks/paddle_billing — RubyGems publishes no active-install counts; this is an order-of-magnitude estimate from the pay gem's popularity among Rails apps (millions of cumulative downloads) discounted to the subset that enable Paddle Billing webhooks, whose…

Order-of-magnitude estimate by the model from install counts, market share and public scan data it knows; verify before quoting.

Description

Pay is a payments engine for Ruby on Rails 6.0 and higher. Prior to 11.6.2, Pay::Webhooks::PaddleBillingController#valid_signature? in app/controllers/pay/webhooks/paddle_billing_controller.rb compares the computed 64-character SHA-256 HMAC with the attacker-controlled h1 token from the Paddle-Signature header using Ruby String#==. An unauthenticated remote attacker who can repeatedly submit requests to /pay/webhooks/paddle_billing and obtain sufficiently precise timing measurements can infer matching digest prefixes and recover a valid signature. A forged accepted webhook is enqueued through Pay::Webhooks::ProcessJob and can cause a host application to update billing state, provision paid features, record refunds, or trigger customer notifications. This issue is fixed in version 11.6.2.

Weakness
CWE-208
Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

In the news

No ingested article mentions this CVE yet.