CVE-2026-33661
Description
Pay is an open-source payment SDK extension package for various Chinese payment services. Prior to version 3.7.20, the 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. This allows forging fake WeChat Pay payment success notifications, potentially causing applications to mark orders as paid without actual payment. Version 3.7.20 fixes the issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
yansongda/payPackagist | < 3.7.20 | 3.7.20 |
Affected products
1Patches
126987ebf789ffix: 修复 localhost 签名验证绕过漏洞 (GHSA-q938-ghwv-8gvc) (#1131)
12 files changed · +106 −46
CHANGELOG.md+4 −0 modified@@ -5,6 +5,10 @@ - feat: 新增 PayPal 支付 (#1127) - feat: 新增 Stripe 支付 (#1130) +### fixed + +- fix: 修复 localhost 签名验证绕过漏洞 (GHSA-q938-ghwv-8gvc) (#1131) + ## v3.7.19 ### added
src/Functions.php+0 −12 modified@@ -247,10 +247,6 @@ function get_wechat_sign_v2(array $config, array $payload, bool $upper = true): */ function verify_wechat_sign(ResponseInterface|ServerRequestInterface $message, array $params): void { - if ($message instanceof ServerRequestInterface && 'localhost' === $message->getUri()->getHost()) { - return; - } - $wechatSerial = $message->getHeaderLine('Wechatpay-Serial'); $timestamp = $message->getHeaderLine('Wechatpay-Timestamp'); $random = $message->getHeaderLine('Wechatpay-Nonce'); @@ -730,10 +726,6 @@ function get_paypal_access_token(array $params): string */ function verify_paypal_webhook_sign(ServerRequestInterface $request, array $params): void { - if ('localhost' === $request->getUri()->getHost()) { - return; - } - $config = get_provider_config('paypal', $params); $webhookId = $config['webhook_id'] ?? null; @@ -811,10 +803,6 @@ function get_stripe_url(array $config, ?Collection $payload): string */ function verify_stripe_webhook_sign(ServerRequestInterface $request, array $params): void { - if ('localhost' === $request->getUri()->getHost()) { - return; - } - $config = get_provider_config('stripe', $params); $webhookSecret = $config['webhook_secret'] ?? null;
tests/FunctionTest.php+2 −14 modified@@ -247,7 +247,7 @@ public function testVerifyWechatSign() 200, [ 'Wechatpay-Nonce' => 'e59e78a6c3f7dfd7e84aabee71be0452', - 'Wechatpay-Signature' => 'Bb10ZUsON47E/qLjecjk6ESLt7obZCvCCAXAEoD1Q+K548fz9h6YBgR3PZzviTmjsA3/r22qEC3r/yelFAn4pl4rJBGqrjo4ODJkOPlaDnHZwYotDvf6RcASpKB9ExCb33hAijHCiMzr9V9skNrj5F9eXc96lNZN3R5MVLsTF97nV922JIzyCrZ668khYPrn1jl5pCBpYDQ3rskgmZ+nnjg7M9vRAfTowEydSEGtsKjXUSaaKui2RDUuX8ZwxVcBTRng978Gh9s4mdRxs+mlv3gP1xQHdpa0mYMG0yGzLcWOTgrkt27sAwFnuXj9WtlEAgz/1DYntujKPxilMVGRow==', + 'Wechatpay-Signature' => 'Ut3dG8cMx5W1lbSQhHay068F6khScuPQJM/Z9+suaaSkbYUspFRlkdp2VR/6w5UMvioN0EveSgfypQFVqmT6tI//cWrA1J9rlnKmZ+FgdCMqg7FQnpMRzc1Ap+3mZMtN9GrzYqp/UdgotX6HRfGL3hP8pG1YuijHNrL0QRS17bNYwZX8Mj3qLKUQRpqbfE+TC5yvzh1gEVPBFTwvZdZvXIQpjC/sB2QDSvo72CWgm4huh1h/kMzsrsO+wXXLqDfU01YX8aLbBrjvpcob50lc5XZ2WX5nBbpJXaRatIhBUmkR/ccrQhxWN7YqEobBGK/2DYhr6e6CvTgVdpZUUEcMFw==', 'Wechatpay-Timestamp' => '1626444144', 'Wechatpay-Serial' => '45F59D4DABF31918AFCEC556D5D2C6E376675D57', ], @@ -256,15 +256,11 @@ public function testVerifyWechatSign() verify_wechat_sign($response, []); self::assertTrue(true); - $serverRequest = new ServerRequest('POST', 'http://localhost'); - verify_wechat_sign($serverRequest, []); - self::assertTrue(true); - $response = new Response( 200, [ 'Wechatpay-Nonce' => 'e59e78a6c3f7dfd7e84aabee71be0452', - 'Wechatpay-Signature' => 'Bb10ZUsON47E/qLjecjk6ESLt7obZCvCCAXAEoD1Q+K548fz9h6YBgR3PZzviTmjsA3/r22qEC3r/yelFAn4pl4rJBGqrjo4ODJkOPlaDnHZwYotDvf6RcASpKB9ExCb33hAijHCiMzr9V9skNrj5F9eXc96lNZN3R5MVLsTF97nV922JIzyCrZ668khYPrn1jl5pCBpYDQ3rskgmZ+nnjg7M9vRAfTowEydSEGtsKjXUSaaKui2RDUuX8ZwxVcBTRng978Gh9s4mdRxs+mlv3gP1xQHdpa0mYMG0yGzLcWOTgrkt27sAwFnuXj9WtlEAgz/1DYntujKPxilMVGRow==', + 'Wechatpay-Signature' => 'Ut3dG8cMx5W1lbSQhHay068F6khScuPQJM/Z9+suaaSkbYUspFRlkdp2VR/6w5UMvioN0EveSgfypQFVqmT6tI//cWrA1J9rlnKmZ+FgdCMqg7FQnpMRzc1Ap+3mZMtN9GrzYqp/UdgotX6HRfGL3hP8pG1YuijHNrL0QRS17bNYwZX8Mj3qLKUQRpqbfE+TC5yvzh1gEVPBFTwvZdZvXIQpjC/sB2QDSvo72CWgm4huh1h/kMzsrsO+wXXLqDfU01YX8aLbBrjvpcob50lc5XZ2WX5nBbpJXaRatIhBUmkR/ccrQhxWN7YqEobBGK/2DYhr6e6CvTgVdpZUUEcMFw==', 'Wechatpay-Timestamp' => '1626444144', 'Wechatpay-Serial' => '45F59D4DABF31918AFCEC556D5D2C6E376675D57', ], @@ -768,14 +764,6 @@ public function testGetPaypalAccessTokenFresh() self::assertNotEmpty(Pay::get(ConfigInterface::class)->get('paypal.default._access_token_expiry')); } - public function testVerifyPaypalWebhookSignLocalhost() - { - $request = new ServerRequest('POST', 'http://localhost', [], '{}'); - - verify_paypal_webhook_sign($request, []); - self::assertTrue(true); - } - public function testVerifyPaypalWebhookSignMissingWebhookId() { Pay::get(ConfigInterface::class)->set('paypal.default.webhook_id', '');
tests/Plugin/Paypal/V2/Pay/CallbackPluginTest.php+19 −1 modified@@ -4,10 +4,15 @@ namespace Yansongda\Pay\Tests\Plugin\Paypal\V2\Pay; +use GuzzleHttp\Client; +use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\ServerRequest; +use Mockery; +use Yansongda\Artful\Contract\HttpClientInterface; use Yansongda\Artful\Exception\InvalidParamsException; use Yansongda\Artful\Rocket; use Yansongda\Pay\Exception\Exception; +use Yansongda\Pay\Pay; use Yansongda\Pay\Plugin\Paypal\V2\Pay\CallbackPlugin; use Yansongda\Pay\Tests\TestCase; @@ -40,7 +45,20 @@ public function testNormalCallback() 'resource' => ['id' => 'ORDER_123', 'status' => 'APPROVED'], ]); - $request = new ServerRequest('POST', 'http://localhost', [ + $tokenResponse = new Response(200, [], json_encode([ + 'access_token' => 'test_token_123', + 'token_type' => 'Bearer', + 'expires_in' => 32400, + ])); + $verifyResponse = new Response(200, [], json_encode([ + 'verification_status' => 'SUCCESS', + ])); + + $http = Mockery::mock(Client::class); + $http->shouldReceive('sendRequest')->andReturn($tokenResponse, $verifyResponse); + Pay::set(HttpClientInterface::class, $http); + + $request = new ServerRequest('POST', 'https://pay.yansongda.cn/paypal/notify', [ 'PAYPAL-TRANSMISSION-ID' => 'test-id', 'PAYPAL-TRANSMISSION-TIME' => '2024-01-01T00:00:00Z', 'PAYPAL-TRANSMISSION-SIG' => 'test-sig',
tests/Plugin/Stripe/V1/Pay/CallbackPluginTest.php+17 −3 modified@@ -35,7 +35,15 @@ public function testMissingRequestThrowsException() public function testInvalidJsonBodyThrowsException() { - $request = new ServerRequest('POST', 'http://localhost', [], 'not-valid-json'); + $body = 'not-valid-json'; + $timestamp = time(); + $webhookSecret = 'whsec_stripe_webhook_secret'; + $expectedSig = hash_hmac('sha256', $timestamp.'.'.$body, $webhookSecret); + $signatureHeader = 't='.$timestamp.',v1='.$expectedSig; + + $request = new ServerRequest('POST', 'https://pay.yansongda.cn/stripe/notify', [ + 'Stripe-Signature' => $signatureHeader, + ], $body); $rocket = new Rocket(); $rocket->setParams(['_request' => $request, '_params' => []]); @@ -59,8 +67,14 @@ public function testNormalCallback() ], ]); - // localhost skips signature verification in CallbackPlugin - $request = new ServerRequest('POST', 'http://localhost', [], $body); + $timestamp = time(); + $webhookSecret = 'whsec_stripe_webhook_secret'; + $expectedSig = hash_hmac('sha256', $timestamp.'.'.$body, $webhookSecret); + $signatureHeader = 't='.$timestamp.',v1='.$expectedSig; + + $request = new ServerRequest('POST', 'https://pay.yansongda.cn/stripe/notify', [ + 'Stripe-Signature' => $signatureHeader, + ], $body); $rocket = new Rocket(); $rocket->setParams(['_request' => $request, '_params' => []]);
tests/Plugin/Stripe/V1/VerifyWebhookSignTest.php+5 −4 modified@@ -14,14 +14,15 @@ class VerifyWebhookSignTest extends TestCase { - public function testLocalhostSkipsVerification() + public function testLocalhostNoLongerSkipsVerification() { $request = new ServerRequest('POST', 'http://localhost', [], '{}'); - // Should not throw — localhost always skips verification - verify_stripe_webhook_sign($request, []); + // localhost should no longer skip verification — missing Stripe-Signature should throw SIGN_EMPTY + self::expectException(InvalidSignException::class); + self::expectExceptionCode(Exception::SIGN_EMPTY); - self::assertTrue(true); + verify_stripe_webhook_sign($request, []); } public function testMissingWebhookSecretThrowsException()
tests/Plugin/Wechat/V3/CallbackPluginTest.php+2 −2 modified@@ -23,10 +23,10 @@ public function testNormal() { $request = new ServerRequest( 'POST', - 'http://localhost', + 'https://pay.yansongda.cn/wechat/notify', [ 'Wechatpay-Nonce' => 'e59e78a6c3f7dfd7e84aabee71be0452', - 'Wechatpay-Signature' => 'Bb10ZUsON47E/qLjecjk6ESLt7obZCvCCAXAEoD1Q+K548fz9h6YBgR3PZzviTmjsA3/r22qEC3r/yelFAn4pl4rJBGqrjo4ODJkOPlaDnHZwYotDvf6RcASpKB9ExCb33hAijHCiMzr9V9skNrj5F9eXc96lNZN3R5MVLsTF97nV922JIzyCrZ668khYPrn1jl5pCBpYDQ3rskgmZ+nnjg7M9vRAfTowEydSEGtsKjXUSaaKui2RDUuX8ZwxVcBTRng978Gh9s4mdRxs+mlv3gP1xQHdpa0mYMG0yGzLcWOTgrkt27sAwFnuXj9WtlEAgz/1DYntujKPxilMVGRow==', + 'Wechatpay-Signature' => 'NmmOwkXg89J9UP9gnoGeGZUdSflYhOzD/Imxv0SZf09+42Yn+u8DHQs/QcsOtD1O9hi38PizLnyMQ7NyqkQqVZCu7ID532FOiKkU6qIhrrCrm8w5ktJTXUorH8gEQtxZSKJ0Z0I/fsOBhnvoBRRlIyvEwoESAcJuyJYCgQuvFaqGYDOjLW7umTdO0vUZnH9TJfxfziLxwEYoH09D43H+hXL4oKAF+aIdAiWyS/CwnE4BB8j4NGsCi4v4cAZkJjqV45koAtzXVBzYjccURNSRUYOZv9IW7CqOFmOWsmAN5bVncs4S89lMNW+UIqNRx4tpIrU4CuX81V0tVFcweKnqNQ==', 'Wechatpay-Timestamp' => '1626444144', 'Wechatpay-Serial' => '45F59D4DABF31918AFCEC556D5D2C6E376675D57', ],
tests/Plugin/Wechat/V3/VerifySignaturePluginTest.php+1 −1 modified@@ -38,7 +38,7 @@ public function testNormal() 200, [ 'Wechatpay-Nonce' => 'e59e78a6c3f7dfd7e84aabee71be0452', - 'Wechatpay-Signature' => 'Bb10ZUsON47E/qLjecjk6ESLt7obZCvCCAXAEoD1Q+K548fz9h6YBgR3PZzviTmjsA3/r22qEC3r/yelFAn4pl4rJBGqrjo4ODJkOPlaDnHZwYotDvf6RcASpKB9ExCb33hAijHCiMzr9V9skNrj5F9eXc96lNZN3R5MVLsTF97nV922JIzyCrZ668khYPrn1jl5pCBpYDQ3rskgmZ+nnjg7M9vRAfTowEydSEGtsKjXUSaaKui2RDUuX8ZwxVcBTRng978Gh9s4mdRxs+mlv3gP1xQHdpa0mYMG0yGzLcWOTgrkt27sAwFnuXj9WtlEAgz/1DYntujKPxilMVGRow==', + 'Wechatpay-Signature' => 'Ut3dG8cMx5W1lbSQhHay068F6khScuPQJM/Z9+suaaSkbYUspFRlkdp2VR/6w5UMvioN0EveSgfypQFVqmT6tI//cWrA1J9rlnKmZ+FgdCMqg7FQnpMRzc1Ap+3mZMtN9GrzYqp/UdgotX6HRfGL3hP8pG1YuijHNrL0QRS17bNYwZX8Mj3qLKUQRpqbfE+TC5yvzh1gEVPBFTwvZdZvXIQpjC/sB2QDSvo72CWgm4huh1h/kMzsrsO+wXXLqDfU01YX8aLbBrjvpcob50lc5XZ2WX5nBbpJXaRatIhBUmkR/ccrQhxWN7YqEobBGK/2DYhr6e6CvTgVdpZUUEcMFw==', 'Wechatpay-Timestamp' => '1626444144', 'Wechatpay-Serial' => '45F59D4DABF31918AFCEC556D5D2C6E376675D57', ],
tests/Provider/PaypalTest.php+34 −1 modified@@ -2,8 +2,12 @@ namespace Yansongda\Pay\Tests\Provider; +use GuzzleHttp\Client; +use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\ServerRequest; +use Mockery; use Psr\Http\Message\ResponseInterface; +use Yansongda\Artful\Contract\HttpClientInterface; use Yansongda\Artful\Exception\Exception; use Yansongda\Artful\Exception\InvalidParamsException; use Yansongda\Artful\Plugin\AddPayloadBodyPlugin; @@ -70,7 +74,20 @@ public function testCallback() 'resource' => ['id' => 'ORDER_123', 'status' => 'APPROVED'], ]); - $request = new ServerRequest('POST', 'http://localhost', [ + $tokenResponse = new Response(200, [], json_encode([ + 'access_token' => 'test_token_123', + 'token_type' => 'Bearer', + 'expires_in' => 32400, + ])); + $verifyResponse = new Response(200, [], json_encode([ + 'verification_status' => 'SUCCESS', + ])); + + $http = Mockery::mock(Client::class); + $http->shouldReceive('sendRequest')->andReturn($tokenResponse, $verifyResponse); + Pay::set(HttpClientInterface::class, $http); + + $request = new ServerRequest('POST', 'https://pay.yansongda.cn/paypal/notify', [ 'PAYPAL-TRANSMISSION-ID' => 'test-id', 'PAYPAL-TRANSMISSION-TIME' => '2024-01-01T00:00:00Z', 'PAYPAL-TRANSMISSION-SIG' => 'test-sig', @@ -92,10 +109,26 @@ public function testCallbackWithArray() 'resource' => ['id' => 'CAPTURE_456', 'status' => 'COMPLETED'], ]); + $tokenResponse = new Response(200, [], json_encode([ + 'access_token' => 'test_token_456', + 'token_type' => 'Bearer', + 'expires_in' => 32400, + ])); + $verifyResponse = new Response(200, [], json_encode([ + 'verification_status' => 'SUCCESS', + ])); + + $http = Mockery::mock(Client::class); + $http->shouldReceive('sendRequest')->andReturn($tokenResponse, $verifyResponse); + Pay::set(HttpClientInterface::class, $http); + $result = Pay::paypal()->callback([ 'headers' => [ 'PAYPAL-TRANSMISSION-ID' => 'test-id', + 'PAYPAL-TRANSMISSION-TIME' => '2024-01-01T00:00:00Z', 'PAYPAL-TRANSMISSION-SIG' => 'test-sig', + 'PAYPAL-CERT-URL' => 'https://api.sandbox.paypal.com/v1/notifications/certs/CERT-123', + 'PAYPAL-AUTH-ALGO' => 'SHA256withRSA', ], 'body' => $body, ]);
tests/Provider/StripeTest.php+14 −3 modified@@ -60,8 +60,14 @@ public function testCallback() ], ]); - // localhost skips signature verification - $request = new ServerRequest('POST', 'http://localhost', [], $body); + $timestamp = time(); + $webhookSecret = 'whsec_stripe_webhook_secret'; + $expectedSig = hash_hmac('sha256', $timestamp.'.'.$body, $webhookSecret); + $signatureHeader = 't='.$timestamp.',v1='.$expectedSig; + + $request = new ServerRequest('POST', 'https://pay.yansongda.cn/stripe/notify', [ + 'Stripe-Signature' => $signatureHeader, + ], $body); $result = Pay::stripe()->callback($request); @@ -83,8 +89,13 @@ public function testCallbackWithArray() ], ]); + $timestamp = time(); + $webhookSecret = 'whsec_stripe_webhook_secret'; + $expectedSig = hash_hmac('sha256', $timestamp.'.'.$body, $webhookSecret); + $signatureHeader = 't='.$timestamp.',v1='.$expectedSig; + $result = Pay::stripe()->callback([ - 'headers' => ['Stripe-Signature' => 'test-sig'], + 'headers' => ['Stripe-Signature' => $signatureHeader], 'body' => $body, ]);
tests/Provider/WechatTest.php+4 −4 modified@@ -58,7 +58,7 @@ public function testCancel() 200, [ 'Wechatpay-Nonce' => 'e59e78a6c3f7dfd7e84aabee71be0452', - 'Wechatpay-Signature' => 'Bb10ZUsON47E/qLjecjk6ESLt7obZCvCCAXAEoD1Q+K548fz9h6YBgR3PZzviTmjsA3/r22qEC3r/yelFAn4pl4rJBGqrjo4ODJkOPlaDnHZwYotDvf6RcASpKB9ExCb33hAijHCiMzr9V9skNrj5F9eXc96lNZN3R5MVLsTF97nV922JIzyCrZ668khYPrn1jl5pCBpYDQ3rskgmZ+nnjg7M9vRAfTowEydSEGtsKjXUSaaKui2RDUuX8ZwxVcBTRng978Gh9s4mdRxs+mlv3gP1xQHdpa0mYMG0yGzLcWOTgrkt27sAwFnuXj9WtlEAgz/1DYntujKPxilMVGRow==', + 'Wechatpay-Signature' => 'Ut3dG8cMx5W1lbSQhHay068F6khScuPQJM/Z9+suaaSkbYUspFRlkdp2VR/6w5UMvioN0EveSgfypQFVqmT6tI//cWrA1J9rlnKmZ+FgdCMqg7FQnpMRzc1Ap+3mZMtN9GrzYqp/UdgotX6HRfGL3hP8pG1YuijHNrL0QRS17bNYwZX8Mj3qLKUQRpqbfE+TC5yvzh1gEVPBFTwvZdZvXIQpjC/sB2QDSvo72CWgm4huh1h/kMzsrsO+wXXLqDfU01YX8aLbBrjvpcob50lc5XZ2WX5nBbpJXaRatIhBUmkR/ccrQhxWN7YqEobBGK/2DYhr6e6CvTgVdpZUUEcMFw==', 'Wechatpay-Timestamp' => '1626444144', 'Wechatpay-Serial' => '45F59D4DABF31918AFCEC556D5D2C6E376675D57', ], @@ -98,7 +98,7 @@ public function testClose() 200, [ 'Wechatpay-Nonce' => 'e59e78a6c3f7dfd7e84aabee71be0452', - 'Wechatpay-Signature' => 'Bb10ZUsON47E/qLjecjk6ESLt7obZCvCCAXAEoD1Q+K548fz9h6YBgR3PZzviTmjsA3/r22qEC3r/yelFAn4pl4rJBGqrjo4ODJkOPlaDnHZwYotDvf6RcASpKB9ExCb33hAijHCiMzr9V9skNrj5F9eXc96lNZN3R5MVLsTF97nV922JIzyCrZ668khYPrn1jl5pCBpYDQ3rskgmZ+nnjg7M9vRAfTowEydSEGtsKjXUSaaKui2RDUuX8ZwxVcBTRng978Gh9s4mdRxs+mlv3gP1xQHdpa0mYMG0yGzLcWOTgrkt27sAwFnuXj9WtlEAgz/1DYntujKPxilMVGRow==', + 'Wechatpay-Signature' => 'Ut3dG8cMx5W1lbSQhHay068F6khScuPQJM/Z9+suaaSkbYUspFRlkdp2VR/6w5UMvioN0EveSgfypQFVqmT6tI//cWrA1J9rlnKmZ+FgdCMqg7FQnpMRzc1Ap+3mZMtN9GrzYqp/UdgotX6HRfGL3hP8pG1YuijHNrL0QRS17bNYwZX8Mj3qLKUQRpqbfE+TC5yvzh1gEVPBFTwvZdZvXIQpjC/sB2QDSvo72CWgm4huh1h/kMzsrsO+wXXLqDfU01YX8aLbBrjvpcob50lc5XZ2WX5nBbpJXaRatIhBUmkR/ccrQhxWN7YqEobBGK/2DYhr6e6CvTgVdpZUUEcMFw==', 'Wechatpay-Timestamp' => '1626444144', 'Wechatpay-Serial' => '45F59D4DABF31918AFCEC556D5D2C6E376675D57', ], @@ -136,10 +136,10 @@ public function testCallback() { $request = new ServerRequest( 'POST', - 'http://localhost', + 'https://pay.yansongda.cn/wechat/notify', [ 'Wechatpay-Nonce' => 'e59e78a6c3f7dfd7e84aabee71be0452', - 'Wechatpay-Signature' => 'Bb10ZUsON47E/qLjecjk6ESLt7obZCvCCAXAEoD1Q+K548fz9h6YBgR3PZzviTmjsA3/r22qEC3r/yelFAn4pl4rJBGqrjo4ODJkOPlaDnHZwYotDvf6RcASpKB9ExCb33hAijHCiMzr9V9skNrj5F9eXc96lNZN3R5MVLsTF97nV922JIzyCrZ668khYPrn1jl5pCBpYDQ3rskgmZ+nnjg7M9vRAfTowEydSEGtsKjXUSaaKui2RDUuX8ZwxVcBTRng978Gh9s4mdRxs+mlv3gP1xQHdpa0mYMG0yGzLcWOTgrkt27sAwFnuXj9WtlEAgz/1DYntujKPxilMVGRow==', + 'Wechatpay-Signature' => 'NmmOwkXg89J9UP9gnoGeGZUdSflYhOzD/Imxv0SZf09+42Yn+u8DHQs/QcsOtD1O9hi38PizLnyMQ7NyqkQqVZCu7ID532FOiKkU6qIhrrCrm8w5ktJTXUorH8gEQtxZSKJ0Z0I/fsOBhnvoBRRlIyvEwoESAcJuyJYCgQuvFaqGYDOjLW7umTdO0vUZnH9TJfxfziLxwEYoH09D43H+hXL4oKAF+aIdAiWyS/CwnE4BB8j4NGsCi4v4cAZkJjqV45koAtzXVBzYjccURNSRUYOZv9IW7CqOFmOWsmAN5bVncs4S89lMNW+UIqNRx4tpIrU4CuX81V0tVFcweKnqNQ==', 'Wechatpay-Timestamp' => '1626444144', 'Wechatpay-Serial' => '45F59D4DABF31918AFCEC556D5D2C6E376675D57', ],
tests/TestCase.php+4 −1 modified@@ -43,7 +43,10 @@ protected function setUp(): void 'mch_public_cert_path' => __DIR__.'/Cert/wechatAppPublicKey.pem', 'notify_url' => 'https://pay.yansongda.cn', 'wechat_public_cert_path' => [ - '45F59D4DABF31918AFCEC556D5D2C6E376675D57' => __DIR__.'/Cert/wechatPublicKey.crt', + // 注意:正常情况下此处应配置微信官方公钥(wechatPublicKey.crt),但由于单元测试中的签名 + // 均使用 wechatAppPrivateKey.pem 生成,而 wechatPublicKey.crt 对应的私钥我们并不持有, + // 因此测试环境特殊地将 serial 映射到 wechatAppPublicKey.pem,以保证验签可以通过。 + '45F59D4DABF31918AFCEC556D5D2C6E376675D57' => __DIR__.'/Cert/wechatAppPublicKey.pem', 'yansongda' => __DIR__.'/Cert/wechatPublicKey.crt', ], 'mode' => Pay::MODE_NORMAL,
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/yansongda/pay/commit/26987ebf789f1e7f0a85febb640986ab4289fd7fnvdPatchWEB
- github.com/yansongda/pay/security/advisories/GHSA-q938-ghwv-8gvcnvdExploitVendor AdvisoryWEB
- github.com/advisories/GHSA-q938-ghwv-8gvcghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-33661ghsaADVISORY
- github.com/yansongda/pay/releases/tag/v3.7.20nvdRelease NotesWEB
News mentions
0No linked articles in our index yet.