针对 Hyperswitch payout confirm 漏洞的 Proof-of-concept 与实验环境:在 POST /payouts/{id}/confirm 中,一个 dummy client_secret 加上 amount 会提高已存储的 payout 金额。
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · hyperswitch-payout-confirm-secret
Hyperswitch 2026.09.21.0 - Juspay
payouts_confirm 使用 check_value_present("client_secret") 对 pk_ 进行认证。仅检查存在。不检查相等。Payments confirm 仍然会绑定:authenticate_client_secret 在不匹配时返回 IR_09。confirm 请求体是一个完整的 PayoutCreateRequest。update_payouts_and_payout_attempt 在连接器路由之前写入 amount。
在 payouts confirm 上使用伪造的 client_secret 加上 amount=99900 会存储 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 |
| 认证 | 可发布的 pk_ 加上 payout id;伪造 secret |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1 |
需要可发布密钥(公开,checkout)和 payout id(payout 链接、商户仪表盘、客户端创建响应)。使用伪造 secret 和新的 amount 向 /payouts/{id}/confirm 发送 POST 请求。即使连接器路由返回 400 IR_39(没有符合条件的 payout 连接器),retrieve 仍会显示被提高的金额。写入已经发生。在拥有 payout 处理器的商店上完成履约是下一步。
没有 pk_ 的访客不属于此漏洞。使用 sk_ secret 的 confirm 是商户侧的。不是 shell。在此实验镜像上不是成功的连接器 payout。
与 unsigned Worldpayxml webhook 是同一产品。不同的漏洞。
我阅读了 check_value_present,然后是 payments 的 req_cs != pi_cs,接着是 payouts_core 之前的 update_payouts_and_payout_attempt。pk_ 的认证是“checkout SDK”。secret 本应将浏览器会话绑定到此 payout。Payments 做相等比较。Payouts 只做存在检查。非空的伪造值就足够了。JSON 仍然是一个 create 请求,因此 amount 在 confirm 上并非无操作。
第一个注意到这一点的客户端会在不带 client_secret 的情况下发送 confirm,并得到 MissingRequiredField。仅检查存在。发送真实 secret,你就是付款人。在 payments confirm 上发送伪造值,你会得到 IR_09。这就是对照。在 payouts confirm 上发送伪造值。
已记录的弯路:将 HTTP 400 IR_39 视为“什么都没发生”(retrieve 该 payout);amount 保持 1000 是因为 confirm 省略了 amount(unwrap_or 保留旧值);payout 已经处于终态(Success / Failed / Cancelled);反向 shell。都是表演。证据是在伪造 secret 之后 retrieve 得到 amount=99900,而 payments confirm 仍然返回 IR_09。
然后:创建一个商户、一个 secret key、一个可发布的 pk_、一个 worldpayxml payout 连接器,并以 confirm=false、amount 为 1000 发送 POST /payouts/create。RequiresConfirmation。Payments 伪造 secret 对照。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。伪造 secret 必须返回 IR_09(或 401),并且 retrieve 的 amount 必须保持 1000。
payouts.rs 路由 · authentication.rs · payouts/helpers.rs · core/payouts.rs · payments/helpers.rsGNU Affero GPL v3.0。参见 LICENSE。仅限回环实验环境。无担保。