Respuesta rápida
IDOR y BAC siguen siendo el #1 de OWASP API Security en 2026. La regla: scanners automáticos no los encuentran — requieren contexto de negocio (¿qué hace este endpoint?) y dos cuentas para verificar el access boundary. La metodología: dos cuentas (A y B), capturar requests de A en Burp, swappear IDs/cookies por los de B, observar la respuesta. Si A puede ver/editar/borrar recursos de B, es IDOR. Si un user normal puede llegar a endpoints de admin, es BAC vertical. Bounties típicos: €500-€10.000+ según el impacto.
Setup — dos cuentas en paralelo
El error de principiante: probar IDOR con una sola cuenta. Sin la cuenta B no tienes baseline — no sabes si el server rechaza al user de A o si simplemente el ID no existe.
Stack:
- Burp Suite (Community vale) con dos browsers (Chrome perfil A, Firefox perfil B).
- O dos perfiles del mismo browser + extensiones tipo Auth Analyzer o Autorize.
- Match-and-replace en Burp para swappear cookies automáticamente.
Browser A (Chrome) → Burp Proxy → target.com
Browser B (Firefox) → Burp Proxy → target.com
Captura un request de A, manda a Repeater, cambia solo la cookie/header de auth por la de B (todo lo demás igual). Si la respuesta es la misma que la de A → IDOR confirmado.
[!tip] Auth Analyzer extension Autoriza Burp a re-enviar cada request con la sesión de un user diferente y comparar la respuesta. Lo más rápido para auditar 50+ endpoints sin script.
Las 8 superficies donde aparece IDOR
| # | Superficie | Ejemplo de URL | Test |
|---|---|---|---|
| 1 | Path parameter numérico | /api/users/12345 | 12344, 12346, 0, -1 |
| 2 | Path parameter UUID | /api/orders/abc-def-ghi | UUID de B obtenido por otra vía |
| 3 | Query parameter | /profile?userId=42 | Cambiar a 43 |
| 4 | Body JSON field | {"userId": 42, "data": "..."} | Swap userId al de B |
| 5 | Header custom | X-User-Id: 42 | Cambiar a 43 |
| 6 | Cookie value | Cookie: uid=42; ... | Cambiar a 43 |
| 7 | Hidden form field | <input type="hidden" name="user_id" value="42"> | Cambiar antes de submit |
| 8 | JWT claim | {"sub": "42", "role": "user"} | Re-firmar con sub=43 si firma débil |
El truco de oro: muchas apps validan el ID en el path pero no el del body. Si el endpoint es POST /api/users/42/profile con body {"userId": 42, "newName": "..."}, prueba dejar el path en 42 pero meter userId: 43 en el body. Frecuentemente el server ignora el path y confía en el body.
Cómo obtener IDs ajenos
Sin IDs de la cuenta B (o de otros users) no puedes confirmar IDOR. Fuentes:
- Tu propia cuenta B: regístrala con email distinto y observa qué IDs aparecen.
- Endpoints de listado público:
/users/search,/api/leaderboard,/comments?postId=X. - Funcionalidades que filtran IDs: avatars (
/avatars/USER_ID.jpg), notifications (from_user_id), public posts. - URLs compartidas: invitación, magic link, recibo de compra que incluye order ID.
- Source maps + bundles JS: a veces los routers en frontend listan IDs hardcoded de demos.
- GraphQL introspección + queries de búsqueda sin filtro de visibilidad.
[!warning] Privacy + scope Si encuentras IDOR que filtra PII (email, phone, dirección, DNI), documenta CON tu propia cuenta de control — no tires bulk extraction contra users reales. La mayoría de programs prohíbe extraction de >1-2 records de cuentas no propias.
IDOR horizontal vs vertical
Horizontal — mismo rol, otra identidad. User A accede a recursos de user B:
GET /api/orders/B_ORDER_ID
Authorization: Bearer JWT_DE_A
← 200 OK con datos de B = IDOR horizontal
Vertical — escalación de privilegios. User normal accede a endpoints/funciones de admin:
DELETE /api/admin/users/12
Authorization: Bearer JWT_DE_USER_NORMAL
← 200 OK = BAC vertical
Vertical pesa más en CVSS — usualmente Critical (9.0+). Bounties típicos €5K-€20K+.
Parameter swap — el patrón más rentable
Casi todos los IDOR rentables vienen de swappear un parámetro en un endpoint que parece inofensivo:
Cambio de email — sin verificación
PUT /api/users/me/email
{"email": "atacante@evil.tld", "userId": ID_DE_VICTIMA}
Server actualiza email del userId del body, ignora el me del path → reset password vía email controlado → ATO.
Cambio de password — oldPassword no verificado
POST /api/users/CHANGE_PASSWORD
{"userId": ID_VICTIMA, "newPassword": "atacante"}
Endpoint no pide oldPassword. Tipicamente bounty €3K-€8K.
Cancelación de orden — refund a cuenta atacante
POST /api/orders/B_ORDER_ID/refund
{"refundTo": "atacante_bank_account"}
Asignación de rol en team
POST /api/teams/T_ID/members
{"userId": ATACANTE_ID, "role": "owner"}
Si el endpoint no verifica que el actor sea owner del team → cualquier user puede unirse como owner a cualquier team.
Hidden parameters — los que generan bounties grandes
Muchos endpoints aceptan parámetros que no aparecen en requests legítimos del UI. El backend los procesa si están presentes, pero el frontend nunca los manda. Resultado: features no documentadas, a veces de admin.
Wordlist de parámetros frecuentes
admin, isAdmin, is_admin, role, userRole, accountType
debug, test, dev, sandbox, preview
force, bypass, override, skipAuth
verified, isVerified, emailVerified
status, accountStatus, suspended, banned
internal, system, super, root
hidden, public, visible
Tools
# Arjun — descubre parámetros HTTP ocultos
arjun -u https://target.com/api/users -m GET
# Param Miner (Burp extension)
# Right-click request → Extensions → Param Miner → Guess params
Ejemplos de bounty real con hidden params
POST /api/userscon body normal{email, password}+ extra{"role": "admin"}→ user nuevo creado como admin.PUT /api/posts/Xcon extra{"approvedBy": "system"}→ bypassea cola de moderación.GET /api/orders/X?debug=true→ response expandida con campos internos (PII, internal IDs, cost).
Function-level BAC — endpoints que el frontend no llama
El UI normal nunca llama a /api/admin/users desde un user normal — pero el endpoint sigue existiendo y a veces no chequea el rol.
Cómo encontrarlos
- Login como admin (test account si el program lo permite, o user normal con permisos altos).
- Captura todos los endpoints que el admin dashboard llama.
- Logout, login como user normal.
- Re-tira los mismos endpoints. ¿Hay alguno que responda 200?
Frecuentemente encuentras endpoints que verifican el token (auth) pero no el rol (authorization).
admin → GET /api/admin/users → 200 [lista de users]
user → GET /api/admin/users → 200 [lista de users] ← BAC vertical
Method swap
Algunos endpoints solo validan el método HTTP correcto. Prueba:
POST /api/admin/users → 403 Forbidden
GET /api/admin/users → 200 OK ← BAC
PUT /api/admin/users/42 → 403 Forbidden
PATCH /api/admin/users/42 → 200 OK ← BAC
Trailing slash + extension trick
Algunos WAFs filtran rutas exactas. Prueba variantes:
/api/admin/users → 403
/api/admin/users/ → 200 ← trailing slash bypass
/api/admin/users.json → 200 ← extension
/api/admin/users;.css → 200 ← matrix params
/api/admin/users%20 → 200 ← trailing whitespace
/api/Admin/users → 200 ← case
/api/admin//users → 200 ← double slash
IDOR en GraphQL
GraphQL multiplica la superficie: un solo endpoint expone N queries. El control de acceso suele estar a nivel de resolver, no de field — muy fácil olvidarse de alguno.
Test pattern
query {
user(id: "OTRO_USER_ID") {
email
phoneNumber
addresses { street }
paymentMethods { last4 }
}
}
Si la app no chequea ownership en el resolver de user, lo devuelve. Repite con node(id: ...) (interface common en relay) y con queries de búsqueda sin filtro de visibilidad.
Mutations
mutation {
updateUser(id: "VICTIMA_ID", input: { email: "atacante@evil.tld" }) {
id
}
}
Muchos backends GraphQL verifican que el user está autenticado pero no que sea owner del id que pide modificar.
Reporting tips
- Severity boost: si el IDOR filtra PII regulado (DNI, datos médicos, financieros) → impact privacy, GDPR.
- Account takeover chain: si IDOR permite cambiar email → ATO inmediato, severity Critical.
- Bulk extraction warning: documenta el patrón con 2-3 records de tu cuenta + cuenta control. NO extraigas miles.
- Bypass docs: lista cada filtro intentado por el server (path validation, body validation, method check) y cómo lo bypaseaste — sube el reward y el dev fix más sólido.
Hunting checklist
- Setup dos cuentas (A y B) en paralelo con Burp/Auth Analyzer.
- Mapea todos los endpoints que aceptan ID en path, query, body, header o cookie.
- Swap ID con sesión de B, observa respuesta.
- Prueba todas las acciones (GET / PUT / DELETE / POST) — algunas validan GET pero no DELETE.
- Hidden parameters con Arjun + Param Miner.
- Login como admin (si tienes), captura endpoints admin, reproduce con user normal.
- Method swap + trailing slash + extension tricks en endpoints 403.
- GraphQL: prueba
user(id),node(id), queries de listado sin filtro. - Cross-tenant: si la app es multi-tenant, prueba accesos cross-org.
- Documenta con 2-3 records máx, never bulk extract.
Labs relacionados
Practica IDOR horizontal/vertical, hidden params y BAC function-level en labs de IDOR y BAC.
Practica esto en un lab
Idor Api Newsletter Suscriptores
Sigue aprendiendo · cuenta gratis
Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.
Hay un payload extra al final
Los 12 parámetros ocultos que tests automáticos no detectan pero generan bounties de €1500-€5000 con regularidad.
5 €/mes · cancela cuando quieras
Artículos relacionados
Client-side admin bypass — boolean manipulation + BAC en SPA moderna
Report real Quora: SPA con isAdmin boolean en localStorage que controla UI + backend que no valida server-side. Cómo encadenar boolean flip con BAC para admin takeover.
IDOR en API de newsletters — la UI lo oculta, la API lo regala
Un endpoint sin comprobación de autorización en servidor. Un parámetro público en la URL. Acceso a la lista de suscriptores de cualquier newsletter de una red social profesional.
Mass PII Extraction vía GraphQL — 93 perfiles reales en 1 hora
Un endpoint GraphQL de sincronización de contactos sin rate limiting, sin verificación de propiedad y con batching de 200 números por petición. Resolución teléfono → identidad real.