
Hyperswitch Worldpayxml webhook में unauthenticated flaw (CWE-345/306) के लिए proof-of-concept, जो SETTLED XML को forge करके PSP capture के बिना payments को succeeded mark करता है।
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · hyperswitch-unsigned-webhook
Hyperswitch 2026.09.21.0 - Juspay
Worldpayxml::verify_webhook_source Ok(true) लौटाता है, इस टिप्पणी के साथ कि सत्यापन mTLS के माध्यम से किया जाता है। इस रूट पर कोई mTLS नहीं है। यह फ़ंक्शन बॉडी और हेडर को अनदेखा करता है। incoming.rs फिर source_verified पर भरोसा करता है और बिना किसी PSync के HandleResponse लेता है। LastEvent::Settled PaymentIntentSuccess पर मैप होता है। डिफ़ॉल्ट IncomingWebhook एल्गोरिदम NoAlgorithm है। BitPay और Shift4 इसे इनहेरिट करते हैं। Worldpayxml तो उस तक भी नहीं पहुँचता। यह शॉर्ट-सर्किट कर देता है।
अप्रमाणित डमी SETTLED XML भुगतान को सफल चिह्नित कर देता है। कोई Worldpay कैप्चर नहीं। कोई क्लाइंट सर्ट नहीं।
| ID | अभी तक कोई CVE नहीं |
| CWE | CWE-345, CWE-306 |
| CVSS | High: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N |
| Product | Hyperswitch |
| Affected | 2026.09.21.0 तक Worldpayxml इनबाउंड वेबहुक्स |
| Auth | अप्रमाणित; merchant_id और orderCode चाहिए |
| License | GNU Affero GPL v3.0 |
| Lab | केवल 127.0.0.1 |
merchant_id (हर Hyperswitch डैशबोर्ड URL में मौजूद) और orderCode चाहिए जो attempt के connector_transaction_id के बराबर हो। /webhooks/{merchant_id}/worldpayxml पर अहस्ताक्षरित SETTLED POST करें। यदि source_verified false होता, तो incoming Trigger करता और कनेक्टर को PSync करता। Worldpayxml कभी उस रास्ते पर नहीं जाता। Intent Charged हो जाता है। Lab: status=succeeded। डमी XML। कोई PSP नहीं।
पेमेंट आईडी का अनुमान लगाना बग नहीं है। जिस आईडी को आप पहले ही देख चुके हैं, उसके लिए SETTLED को फ़ोर्ज करना बग है। यह शेल नहीं है। यह लाइव Worldpay सेटलमेंट नहीं है।
एक ही उत्पाद, अलग बग: payout confirm unbound client_secret।
मैंने Ok(true) पढ़ा, फिर HandleResponse बनाम Trigger, फिर Settled -> PaymentIntentSuccess। टिप्पणी mTLS कहती है। Lab POST में कोई क्लाइंट सर्ट नहीं है।
पहला क्लाइंट जो इसे देखेगा, वह requires_confirmation के विरुद्ध वेबहुक POST करेगा। Incoming उस भुगतान को Charged नहीं करेगा जो अभी confirmation से बाहर नहीं निकला। Attempt पर स्टैम्प लगाएँ, या requires_capture / processing तक प्रतीक्षा करें। Lab स्टैम्प लगाता है। वह स्टैम्प एक lab फ़िक्स्चर है। एक लाइव attempt में पहले से ही कनेक्टर आईडी होती है। वेबहुक में नहीं होती।
पहले से दर्ज गलत रास्ते: उस कनेक्टर पर हस्ताक्षरित HMAC जो वास्तव में सत्यापित करता है (यह पथ नहीं करता); वेबहुक HTTP 200 को ओरेकल मानना (GET /payments/{id} को तब तक पोल करें जब तक status=succeeded न हो जाए); orderCode जो connector_transaction_id नहीं है; एक रिवर्स शेल। नाटक।
फिर: merchant, API key, worldpayxml MCA, confirm=false के साथ payment, connector_transaction_id स्टैम्प करें, अहस्ताक्षरित SETTLED, retrieve।
cd lab
./run.sh
लक्ष्य केवल http://127.0.0.1:18082। run.sh कॉन्फ़िग और माइग्रेशन के लिए टैग 2026.09.21.0 को lab/hyperswitch-src में क्लोन करता है।
IOC status_before=requires_confirmation
IOC webhook status=200 unsigned lastEvent=SETTLED
IOC poll status=succeeded
SUCCESS Hyperswitch unsigned Worldpayxml webhook Charged
Worldpay notify को सत्यापित करें (हस्ताक्षर / mTLS जिसे रूट वास्तव में टर्मिनेट करता है)। ऐसे कनेक्टर पर HandleResponse न करें जिसने नो-ऑप से Ok(true) लौटाया हो। अहस्ताक्षरित SETTLED को intent को succeeded पर नहीं ले जाना चाहिए।
worldpayxml.rs · transformers.rs · incoming.rs · webhooks.rs · crypto.rsGNU Affero GPL v3.0। देखें LICENSE। केवल लूपबैक lab। कोई वारंटी नहीं।