
Hyperswitchのpayout confirm脆弱性に関するProof-of-conceptおよびラボ: POST /payouts/{id}/confirm にダミーのclient_secretと金額を送信すると、保存されているpayout金額が増加する。
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · hyperswitch-payout-confirm-secret
Hyperswitch 2026.09.21.0 - Juspay
payouts_confirm は pk_ を check_value_present("client_secret") で認証する。存在する。等しいかどうかは見ない。Payments confirm は依然としてバインドする: authenticate_client_secret は不一致時に IR_09 を返す。confirm ボディは完全な PayoutCreateRequest である。update_payouts_and_payout_attempt はコネクタルーティングの前に amount を書き込む。
ダミーの client_secret と amount=99900 を payouts confirm に付けると 99900 が保存される。同じダミーを使った payments confirm は依然として IR_09 である。
| ID | CVE 未採番 |
| CWE | CWE-863, CWE-345 |
| 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 までの payouts confirm |
| 認証 | publishable pk_ と payout id; ダミーシークレット |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1 のみ |
publishable key (公開、チェックアウト用) と payout id (payout リンク、マーチャントダッシュボード、クライアントの作成レスポンス) が必要である。ダミーシークレットと新しい amount を付けて POST /payouts/{id}/confirm を送る。コネクタルーティングが 400 IR_39 (適格な payout コネクタなし) を返しても、retrieve は引き上げられた amount を表示する。書き込みはすでに完了している。payout プロセッサを持つショップでのフルフィルメントが次の段階である。
pk_ を持たないゲストはこのバグではない。シークレット sk_ による confirm はマーチャント側である。シェルではない。このラボイメージ上でのコネクタ payout 成功でもない。
署名なし Worldpayxml webhook と同じ製品。別のバグ。
私は check_value_present を読み、次に payments の req_cs != pi_cs を、次に payouts_core の前の update_payouts_and_payout_attempt を読んだ。pk_ の認証は「チェックアウト SDK」である。シークレットはブラウザセッションをこの payout にバインドするはずである。Payments は等価性をチェックする。Payouts は存在のみをチェックする。空でないダミーで十分である。JSON は依然として create リクエストなので、confirm 時に amount は no-op ではない。
これを見た最初のクライアントは client_secret なしで confirm を送り、MissingRequiredField を受け取るだろう。存在する。本物のシークレットを送ればあなたが支払者である。payments confirm にダミーを送れば IR_09 が返る。それが対照である。payouts confirm にダミーを送る。
すでに記録済みの誤った道: HTTP 400 IR_39 を「何も起きなかった」と扱うこと (payout を retrieve せよ); confirm が amount を省略したため amount が 1000 のままであること (unwrap_or が古い値を保持する); payout がすでに終端状態 (Success / Failed / Cancelled) であること; リバースシェル。茶番である。証拠はダミーシークレット後の retrieve amount=99900 であり、payments confirm は依然として IR_09 である。
次に: マーチャント、シークレットキー、publishable pk_、worldpayxml payout コネクタを作成し、confirm=false amount 1000 で POST /payouts/create を送る。RequiresConfirmation。Payments ダミーシークレット対照。Payouts ダミー 99900。Retrieve。
cd lab
./run.sh
対象は必ず http://127.0.0.1:18083 のみ。webhook ラボと compose プロジェクトを共有しないこと。
IOC amount_before=1000 status_before=requires_confirmation
IOC payments.confirm dummy-secret status=400 IR_09 client_secret mismatch
IOC payouts.confirm dummy-secret status=400 IR_39 no eligible connector
IOC retrieve amount=99900 status=requires_confirmation
SUCCESS Hyperswitch payout confirm unbound client_secret amount raise
payments が行うのと同じ方法で client_secret を payouts.client_secret と比較し、そのチェックが通るまで confirm 時に PayoutCreateRequest.amount を適用しないこと。ダミーシークレットは IR_09 (または 401) でなければならず、retrieve の amount は 1000 のままでなければならない。
payouts.rs routes · authentication.rs · payouts/helpers.rs · core/payouts.rs · payments/helpers.rsGNU Affero GPL v3.0。LICENSE を参照。ループバックラボのみ。無保証。