Yookassa Webhook Flaw Allowed Forging Payment Confirmations via Single Curl Request

A technical audit of a car rental service uncovered a critical flaw in the Yookassa webhook handler where payment.succeeded events were trusted without verification. The endpoint accepted the event type and gateway_payment_id directly from the client-supplied payload, enabling attackers to mark pending bookings as paid using a simple unauthenticated POST request. The vulnerability existed because the integration did not use Yookassa's optional Webhook-Signature mechanism and avoided IP allowlisting due to proxy infrastructure concerns. Developers addressed the issue by implementing a reverse API call to fetch authoritative payment status from Yookassa before updating records, ensuring fail-closed behavior on errors. New tests cover forgery attempts, amount mismatches, and idempotency, while several additional hardening measures were deliberately deferred to keep the patch minimal and reviewable. The original unit tests had masked the problem by simulating trusted input rather than validating source authenticity.

HabrTranslated from Russian

Read at source

A technical audit of a car rental booking service revealed that the Yookassa webhook endpoint accepted payment.succeeded events at face value, allowing forged payment confirmations with a single unauthenticated curl request.

Original vulnerable implementation

The handler in payment_service.py extracted the event type and gateway_payment_id directly from the incoming JSON payload. It performed only one check: whether the gateway_payment_id existed in the local database. If the event type matched payment.succeeded, the payment status was updated and the booking marked as paid. No signature validation, IP filtering, or secondary verification against the Yookassa API was performed.

Because the gateway_payment_id is returned to the client immediately after payment initiation, any user who created a booking could replay the identifier in a forged webhook and complete the transaction without paying.

Why signature checks were not already in place

Yookassa documentation describes an optional Webhook-Signature header using HMAC-SHA256, yet the integration had never configured a webhook_key. The team rejected IP-based allowlisting because traffic passed through reverse proxies, making reliable extraction of the client IP difficult without weakening the trust model. Instead, the fix relies on an authoritative reverse lookup.

Remediation implemented

The corrected handler now treats the incoming webhook solely as a notification trigger. It immediately calls the Yookassa Payments API using the shop ID and secret key to retrieve the current payment state. Status, amount, and currency are taken exclusively from the API response. Mismatches or API failures result in the webhook returning a 5xx status so that Yookassa will retry later. Final statuses are no longer overwritten by subsequent notifications.

A development mode that lacks API credentials retains the original trusting behavior, as no real payments occur in that environment.

Testing and scope of the patch

  • test_forged_webhook_ignored_when_gateway_says_pending — forged succeeded event ignored when API reports pending
  • test_webhook_amount_mismatch_ignored — status unchanged on amount discrepancy
  • test_webhook_confirmed_success_marks_paid — correct transition when API confirms payment
  • test_webhook_canceled_marks_failed — cancellation properly reflected
  • test_webhook_final_status_not_rewritten — no extra API call for already-final payments
  • test_webhook_unknown_payment_ignored — unknown IDs produce no side effects

The PR added 62 lines to the service and 205 lines of tests. Three further improvements—IP allowlisting, signature verification, and removal of double commits—were intentionally left for separate work to keep the security fix minimal and low-risk.

Meridian digestThe week's most consequential security stories, distilled into one briefing.See the digest

More in Vulnerabilities & Exploits

Telegram for Android Patches Voice Call Vulnerability Enabling Code Execution
Yandex Patches Millions of Stations After eMudhra Certificate Keys Compromised
Cisco ASA and FTD Face DoS Vulnerability in SSL VPN Already Exploited in the Wild