CVE-2026-70658
moderateTiming side-channel in Pay gem's Paddle Billing webhook signature check
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.
| Pay (pay-rails) pay — payments engine for Ruby on Rails | < 11.6.2 (fixed in 11.6.2) |
Order-of-magnitude estimate by the model from install counts, market share and public scan data it knows; verify before quoting.
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 news0 stories
No ingested article mentions this CVE yet.