Condicion de Carrera en Pagos
Operaciones de lectura-modificacion-escritura en pagos sin transacciones de base de datos permiten a los atacantes explotar ventanas de tiempo y gastar el mismo saldo multiples veces.
Cómo Funciona
Una condicion de carrera en pagos ocurre cuando la aplicacion lee el saldo del usuario, verifica si es suficiente y luego deduce el monto en operaciones separadas no atomicas. Si un atacante envia multiples requests simultaneos, todos pueden leer el saldo original antes de que se escriba cualquier deduccion. Cada request ve fondos suficientes y procede con la compra. Por ejemplo, un usuario con $100 envia 10 requests concurrentes para un producto de $50. Los 10 leen $100, los 10 aprueban la compra, resultando en $500 en productos por $100. Esto se llama vulnerabilidad TOCTOU (Time Of Check to Time Of Use) y es comun en e-commerce, monedas in-app y sistemas de wallet.
app.post('/api/purchase', async (req, res) => {
const user = await db.user.findUnique({ where: { id: req.userId } });
if (user.balance < req.body.amount) {
return res.status(400).json({ error: 'Insufficient funds' });
}
await db.user.update({ where: { id: req.userId },
data: { balance: user.balance - req.body.amount } });
await db.order.create({ data: { userId: req.userId, amount: req.body.amount } });
res.json({ success: true });
});app.post('/api/purchase', async (req, res) => {
const result = await db.$transaction(async (tx) => {
const user = await tx.user.findUnique({ where: { id: req.userId } });
if (user.balance < req.body.amount) throw new Error('Insufficient funds');
const updated = await tx.user.update({ where: { id: req.userId },
data: { balance: { decrement: req.body.amount } } });
if (updated.balance < 0) throw new Error('Insufficient funds');
return tx.order.create({ data: { userId: req.userId, amount: req.body.amount } });
});
res.json({ success: true });
});Ejemplo Real
En 2018, Starbucks revelo una condicion de carrera en su sistema de tarjetas de regalo que permitia a los atacantes duplicar saldos haciendo requests de transferencia simultaneos entre tarjetas. El bug fue descubierto a traves de su programa de bug bounty y habia sido explotado para generar credito ilimitado en tiendas.
Cómo Prevenirlo
- Envuelve todas las operaciones de lectura-verificacion-actualizacion de saldo en una transaccion de base de datos
- Usa operaciones atomicas como decrement en vez de leer y restar
- Agrega bloqueo optimista con columnas de version para detectar modificaciones concurrentes
- Implementa llaves de idempotencia para prevenir procesamiento duplicado del mismo request
Tecnologías Afectadas
Data Hogo detecta esta vulnerabilidad automáticamente.
Escanea Tu Repo GratisVulnerabilidades Relacionadas
Manipulacion de Precios
criticalAceptar precios del cliente en vez de buscarlos del lado del servidor permite a los atacantes modificar requests de checkout y comprar productos al precio que elijan.
Feature Flags Expuestos
lowFeature flags incluidos en el bundle de JavaScript del frontend revelan funciones no lanzadas, configuraciones internas de testing y superficies de ataque potenciales a cualquiera que inspeccione el codigo.
Rutas de Debug en Produccion
mediumRutas de desarrollo y testing como /debug, /test, /seed o /api/dev dejadas activas en produccion exponen datos internos, bypassean autenticacion o permiten manipulacion de estado.
Escalacion de Privilegios
highEndpoints de actualizacion de perfil que aceptan campos de rol o permisos del body del request permiten a los usuarios promoverse a admin agregando role: 'admin' a su request de actualizacion.