
Hyperswitch Worldpayxml 웹훅의 인증되지 않은 취약점(CWE-345/306)에 대한 개념 증명으로, PSP 캡처 없이 결제를 성공으로 표시하기 위해 SETTLED XML을 위조합니다.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · hyperswitch-unsigned-webhook
Hyperswitch 2026.09.21.0 - Juspay
Worldpayxml::verify_webhook_source는 검증이 mTLS로 수행된다는 주석과 함께 Ok(true)를 반환합니다. 이 라우트에는 mTLS가 없습니다. 이 함수는 본문과 헤더를 무시합니다. 그런 다음 incoming.rs가 source_verified를 신뢰하고 PSync 없이 HandleResponse를 선택합니다. LastEvent::Settled는 PaymentIntentSuccess로 매핑됩니다. 기본 IncomingWebhook 알고리즘은 NoAlgorithm입니다. BitPay와 Shift4가 이를 상속합니다. Worldpayxml은 그 지점까지 가지도 않습니다. 단락(short-circuit)됩니다.
인증되지 않은 더미 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 |
| 제품 | Hyperswitch |
| 영향 범위 | 2026.09.21.0까지 Worldpayxml 인바운드 웹훅 |
| 인증 | 인증 불필요; merchant_id와 orderCode 필요 |
| 라이선스 | GNU Affero GPL v3.0 |
| 랩 | 127.0.0.1 전용 |
merchant_id(모든 Hyperswitch 대시보드 URL에 포함)와 해당 attempt의 connector_transaction_id와 동일한 orderCode가 필요합니다. 서명되지 않은 SETTLED를 /webhooks/{merchant_id}/worldpayxml에 POST합니다. 만약 source_verified가 false라면 incoming은 Trigger하고 커넥터를 PSync했을 것입니다. Worldpayxml은 결코 그 경로를 타지 않습니다. Intent는 Charged로 갑니다. 랩: status=succeeded. 더미 XML. PSP 없음.
결제 ID를 추측하는 것이 버그가 아닙니다. 이미 본 ID에 대해 SETTLED를 위조하는 것이 버그입니다. 셸도 아닙니다. 실제 Worldpay 정산도 아닙니다.
같은 제품, 다른 버그: payout confirm unbound client_secret.
Ok(true)를 읽고, 그다음 HandleResponse 대 Trigger를, 그다음 Settled -> PaymentIntentSuccess를 읽었습니다. 주석은 mTLS라고 말합니다. 랩 POST에는 클라이언트 인증서가 없습니다.
이것을 처음 보는 클라이언트는 requires_confirmation 상태에 대해 웹훅을 POST할 것입니다. Incoming은 confirmation을 벗어나지 않은 결제를 Charged로 만들지 않습니다. attempt에 스탬프를 찍거나, requires_capture / processing이 될 때까지 기다리십시오. 랩은 스탬프를 찍습니다. 그 스탬프는 랩 픽스처입니다. 실제 attempt에는 이미 커넥터 ID가 있습니다. 웹훅에는 없습니다.
이미 기록된 잘못된 방향들: 실제로 검증하는 커넥터에 서명된 HMAC 적용(이 경로는 검증하지 않음); 웹훅 HTTP 200을 오라클로 취급(GET /payments/{id}를 status=succeeded가 될 때까지 폴링); connector_transaction_id가 아닌 orderCode; 리버스 셸. 극장.
그다음: merchant, API key, worldpayxml MCA, confirm=false인 결제, 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). no-op에서 Ok(true)를 반환한 커넥터에 대해 HandleResponse하지 마십시오. 서명되지 않은 SETTLED가 intent를 succeeded로 이동시켜서는 안 됩니다.
worldpayxml.rs · transformers.rs · incoming.rs · webhooks.rs · crypto.rsGNU Affero GPL v3.0. LICENSE를 참조하십시오. 루프백 랩 전용. 보증 없음.