GitHub Security Advisory: GHSA-xff3-5c9p-2mr4
Package: github.com/QuantumNous/new-api (GO)
Severity: HIGH (CVSS 7.1)
CWE: CWE-345: Insufficient Verification of Data Authenticity, CWE-863: Incorrect Authorization, CWE-1188: Initialization of a Resource with an Insecure Default
Vulnerable versions: < 0.12.10
Patched in: 0.12.10

Summary: New API: Stripe Webhook Signature Bypass via Empty Secret Enables Unlimited Quota Fraud

Details:
## Summary

A critical vulnerability exists in the Stripe webhook handler that allows an **unauthenticated attacker to forge webhook events** and credit arbitrary quota to their account without making any payment. The vulnerability stems from three compounding flaws:

1. The Stripe webhook endpoint does not reject requests when `StripeWebhookSecret` is empty (the default).
2. When the HMAC secret is empty, any attacker can compute valid webhook signatures, effectively **bypassing signature verification entirely**.
3. The `Recharge` function does not validate that the order's `PaymentMethod` matches the callback source, enabling **cross-gateway exploitation** — an order created via any payment method (e.g., Epay) can be fulfilled through a forged Stripe webhook.

## Affected Components

- `controller/topup_stripe.go` — `StripeWebhook()`, `sessionCompleted()`
- `model/topup.go` — `Recharge()`, `RechargeCreem()`, `RechargeWaffo()`
- `controller/topup.go` — `EpayNotify()`
- `controller/topup_creem.go` — `CreemAdaptor.RequestPay()` (missing `PaymentMethod` field)
- `router/api-router.go` — webhook route registered without any guard

## CWE Classification

- **CWE-345**: Insufficient Verification of Data Authenticity
- **CWE-1188**: Initialization with an Insecure Default (empty webhook secret)
- **CWE-863**: Incorrect Authorization (cross-gateway order fulfillment)

## Vulnerability Details

### Flaw 1: Empty Webhook Secret Bypasses Signature Verification

The `StripeWebhookSecret` setting defaults to an empty string `""`. The Stripe Go SDK (`webhook.ConstructEventWithOptions`) does **not** reject empty secrets — it computes `HMAC-SHA256` with an empty key, producing a deterministic and publicly computable signature.

**Vulnerable code** (`controller/topup_stripe.go`):
```go
func StripeWebhook(c *gin.Context) {
    // No check for empty StripeWebhookSecret
    payload, _ := io.ReadAll(c.Request.Body)
    signature := c.GetHeader("Stripe-Signature")
    endpointSecret := setting.StripeWebhookSecret // defaults to ""
    event, err := webhook.ConstructEventWithOptions(payload, signature, endpointSecret, ...)
    // When secret is "", attacker can compute valid HMAC with the same empty key
}
```

The webhook route is unconditionally registered with **no authentication middleware and no rate limiting**:
```go
apiRouter.POST("/stripe/webhook", controller.StripeWebhook)
```

### Flaw 2: Missing `payment_status` Verification

The `sessionCompleted` handler only checks `status == "complete"` but does **not** verify `payment_status == "paid"`. Stripe's `checkout.session.completed` event can fire with `payment_status = "unpaid"` for delayed payment methods (bank transfer, SEPA, Boleto, etc.) or `payment_status = "no_payment_required"` for 100% discount coupons.

Additionally, `checkout.session.async_payment_succeeded` and `checkout.session.async_payment_failed` events are not handled, so delayed payments that ultimately fail are never rolled back.

### Flaw 3: