State Machine Bypass
Direct Endpoint Invocation
Missing Step Validation
Payment Reference Reuse
El endpoint /api/v2/order/confirm acepta un paymentRef de cualquier pedido pasado (incluso pagados hace meses). El servidor verifica que el paymentRef exista en BD pero no que pertenezca al cartId actual ni que el cobro haya sido iniciado en la sesión activa. Permite obtener cualquier producto/suscripción sin pagar.
Flujo Checkout: Intencionado vs. Explotado
CART
→
ADDRESS
→
SHIPPING
→
PAYMENT
⇢ SKIP ⇢
CONFIRM
⚠ El servidor no valida que PAYMENT fue completado antes de aceptar /confirm
# Flujo legítimo: cartId C1 → pago procesado → paymentRef PR-OLD-2025-ABCDEF
# Exploit: cartId nuevo (producto Enterprise €499) sin pasar por /payment
POST /api/v2/order/confirm
{
"cartId": "CART-ENTERPRISE-NEW",
"paymentRef": "PR-OLD-2025-ABCDEF" ← ref de pedido anterior (cualquier importe)
}
→ 200 OK
{
"orderId": "ORD-7821",
"status": "confirmed",
"plan": "enterprise",
"amount_charged": 0.00, ← nunca se cobró
"items": [{"sku":"enterprise-annual","price":499.00}]
}
Pre-condiciones
- Cuenta activa con al menos 1 pedido previo pagado
- Conocer el propio paymentRef (visible en historial de pedidos)
- Cualquier producto/plan en el nuevo carrito
Productos/planes obtenibles gratis
- Plan Enterprise anual (€499)
- Add-ons de capacidad (€49-€199)
- Créditos de API (cualquier pack)
- Licencias de usuario adicionales
Remediación
1) Validar en /confirm que el paymentRef.cartId == cartId del request y que paymentRef.status == "captured".
2) Vincular el paymentRef a la sesión activa con un nonce de sesión (HMAC firmado) que expire en 15 min.
3) Registrar en BD un estado intermedio "payment_initiated" que /confirm requiera como pre-condición obligatoria.