Nuevos labs cada semana — Accede a todos desde 5€/mes

Nivel BásicoGratis

Cómo escribir un bug bounty report que se acepte — estructura y errores comunes

Estructura ideal de un bug bounty report: title, summary, impact, steps to reproduce, PoC, remediation. Los 10 errores que hacen que tu report sea rechazado.

Gorka El Bochi11 de mayo de 202612 min

Respuesta rápida

Un report aceptado tiene 6 partes: title específico (vuln + endpoint + impact), summary de 2 líneas, impact business-oriented (no técnico), steps to reproduce numerados y reproducibles, PoC (video + curl), remediation concreta. Los 3 errores que matan reports: severity inflada, no buscar dupes antes, PoC vago. Bounty típico por report bien escrito vs mismo bug mal escrito: 2-3× diferencia en payout.


La fórmula del título

Title shape que triage acepta sin pensar:

css
[Vulnerability] in [Endpoint] leads to [Impact]

Buenos ejemplos:

  • Stored XSS in /api/v1/comments leads to account takeover
  • IDOR in /api/users/{id}/orders allows reading any user's order history
  • Unauthenticated SSRF in /api/preview-url leads to AWS metadata access

Malos ejemplos:

  • XSS — sin contexto
  • Critical bug in production!!! — clickbait, triage lo descuenta
  • Found a vulnerability — ¿cuál?

[!tip] Test del título Si triage no entiende qué hiciste y qué pasó leyendo sólo el título, está mal escrito. Reescríbelo hasta que un tester sin contexto sepa la severidad y el sink.


Estructura completa — template

markdown
## Summary
[2 líneas — qué encontraste y cuál es el impacto en negocio]

## Severity
[Tu propuesta de severity + CVSS 3.1 con justificación]

## Impact
[Qué puede hacer el atacante. Business language, no técnico.]

## Steps to reproduce
1. ...
2. ...
3. ...

## Proof of Concept
[Video + curl reproducible + screenshots]

## Suggested remediation
[Fix concreto. Si conoces el stack, mejor.]

## References
[Links a docs, CVEs similares, blog posts]

Anatomía de cada sección

Summary — 2 líneas, no más

Triage lee 50 reports al día. Si tu summary requiere 4 párrafos para entenderse, ya perdiste.

Bueno:

El endpoint /api/v1/users/{id}/exports no valida que el id del path coincida con el userId del JWT. Cualquier usuario autenticado puede descargar los exports CSV de cualquier otro user (PII completo: nombre, email, historial de pedidos).

Malo:

Encontré un IDOR muy crítico en la app que permite leer datos de otros usuarios y es muy serio porque expone PII y deberíais arreglarlo cuanto antes.

Impact — business language

Triage suele ser técnico, pero el report sube a managers/legal antes del payout. Habla en su idioma.

Bueno:

Un atacante autenticado puede enumerar exports de los 4.2M usuarios de la plataforma (el id es numérico secuencial). Cada export contiene PII completo regulado por GDPR Art. 4(1). Coste estimado de notificación regulatoria: €15k-€50k. Reputational damage adicional si filtra.

Malo:

Es un IDOR que permite leer datos.

Steps to reproduce — copy-paste-able

Cada paso debe ser ejecutable sin contexto extra. Incluye URLs completas, headers, body raw.

markdown
1. Crear dos cuentas: victim (id=1001) y attacker (id=2042).
2. Login como attacker. Obtener JWT del response (cookie `auth_token`).
3. Hacer la siguiente request con el JWT de attacker pero el id de victim:

```bash
curl -X GET 'https://target.com/api/v1/users/1001/exports' \
  -H 'Authorization: Bearer <attacker_JWT>' \
  -H 'Accept: application/json'
  1. Response: 200 OK con el CSV completo del user 1001.
css

### PoC video — el multiplicador

El video PoC es lo que separa €500 de €2500 en el mismo bug. Triage lo aprueba 3× más rápido.

**Template del video (60-90 segundos):**

0:00-0:10 → Login como attacker. Mostrar user id. 0:10-0:30 → Login como victim en ventana incógnito. Mostrar data privada. 0:30-0:50 → Volver a attacker. Hacer la request maliciosa. Mostrar response. 0:50-1:00 → Comparar data leakeada vs data del victim. Match perfecto. 1:00-1:30 → Cleanup: cerrar sesiones, confirmar logout.

yaml

> [!success] Tools de PoC video
> Loom (web), OBS Studio (desktop), QuickTime (Mac). Sin audio narration  triage prefiere video silencioso con annotations textuales. Subir a YouTube unlisted o al servicio del programa si lo ofrece (H1 Attachments, Bugcrowd Files).

---

## CVSS 3.1 — los 4 vectores que pesan

No necesitas memorizar CVSS, pero entender estos 4 mueve la severity 2 puntos:

| Vector | Subir score | Bajar score |
|---|---|---|
| `AV` (Attack Vector) | Network (N) | Local (L) |
| `AC` (Attack Complexity) | Low (L) | High (H) |
| `PR` (Privileges Required) | None (N) | High (H) |
| `UI` (User Interaction) | None (N) | Required (R) |

**Reglas que aplican el 90% de los casos:**
- Bug accesible vía HTTP  `AV:N`.
- Sin pre-conditions raras  `AC:L`.
- Funciona sin login  `PR:N` (Critical likely).
- Funciona con click del victim  `UI:R` (Medium likely).

Ejemplo: stored XSS auth-required que necesita que la víctima abra una página  `AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N` = 8.3 (High).

---

## Los 10 errores que rechazan reports

| # | Error | Cómo evitarlo |
|---|---|---|
| 1 | No buscar dupes antes de enviar | Search en disclosed reports + Hacktivity con keywords del bug |
| 2 | Severity inflada (CVSS 9.0 para un info leak) |  conservador. Triage premia honestidad. |
| 3 | PoC vago ("intenta esto y verás") | Curl completo + video + steps numerados |
| 4 | No probar tu propio repro antes de enviar | Cierra sesión, abre incógnito, repite tus steps. |
| 5 | Reportar issues out of scope | Lee el scope **completo** antes de empezar |
| 6 | Sin impact statement | Siempre incluye "qué puede hacer el atacante en términos de negocio" |
| 7 | Reportar problemas de configuración trivial (HTTP headers, banner version) | Sólo si hay chain con impacto real |
| 8 | Múltiples bugs en un report | Un report = una vuln. Reports separados se pagan separados. |
| 9 | Tono agresivo en comments | "Esto es Critical, no entiendo cómo no lo veis"  N/A garantizado |
| 10 | No responder a triage en 7 días | Reports en queue se cierran sin payout |

> [!warning] Anti-dupe checklist
> Antes de submit: search en la plataforma con 3 keywords distintas del bug (endpoint, vuln type, payload). Si encuentras incluso uno parecido, lee a fondo. Mejor dejarlo 30 min más analizando que comerse un dupe.

---

## Templates para los reports más comunes

### XSS reflejado

```markdown
## Summary
El parámetro `q` en `/search` refleja sin sanitizar el input del usuario en el contexto HTML, permitiendo ejecución de JavaScript arbitrario.

## Steps to reproduce
1. Visitar: https://target.com/search?q=<script>alert(document.domain)</script>
2. Observar alert con el domain  XSS confirmado.

## Impact
Atacante puede craftear URL maliciosa y enviarla a usuarios autenticados. Al hacer click, el script ejecuta en el contexto del dominio víctima  robo de cookies (no HttpOnly verificado), acciones en nombre del usuario, defacement.

## PoC
[video con steal de cookie y exfil al collaborator]

IDOR

markdown
## Summary
El endpoint `/api/users/{id}/data` no valida ownership entre el `id` del path y el JWT del request. Cualquier user autenticado lee data privada de otros users.

## Steps to reproduce
1. Crear 2 cuentas: A (id=1001), B (id=1002).
2. Login como A. Capturar JWT.
3. Request: GET /api/users/1002/data con JWT de A → 200 OK con data de B.

## Impact
Enumeración completa de PII de los N users de la plataforma (id secuencial). GDPR violation.

SQLi

markdown
## Summary
El parámetro `category` en `/products/list` es vulnerable a SQLi error-based. La payload `' OR 1=1--` dispara error MySQL filtrando structure de la query.

## Steps to reproduce
1. GET /products/list?category=' OR 1=1-- → 500 con MySQL error
2. Confirmar via sqlmap: `sqlmap -u "https://target/products/list?category=1" --dbs`
3. Output: 12 databases, including `users_prod`.

## Impact
Lectura completa de la DB `users_prod` (incluyendo password hashes, emails, payment refs). Posible RCE via `INTO OUTFILE` si MySQL user tiene FILE privilege.

Cómo manejar disagreements con triage

Triage marca tu report como "Informational" o "N/A" cuando crees que es High. Qué hacer:

  1. Lee su justificación 2 veces. Frecuentemente tienen razón.
  2. Responde con datos, no emoción. Cita docs del programa, CVEs equivalentes, blog posts del propio target.
  3. Re-PoC con escenario más claro. Si dijeron "no hay impacto", graba un video mostrando exfil real con el bug.
  4. Escala una vez si sigues sin acuerdo. "Mediator request" en H1, "Request second opinion" en Bugcrowd. Una vez sólo — escalar dos veces marca el report como problemático.
  5. Acepta y aprende. A veces el triage es subjetivo. Mejor un N/A asumido y mantener relación con el programa que ganar la batalla y perder la cuenta.

Hunting checklist — pre-submit

  • Title con shape [Vuln] in [Endpoint] leads to [Impact]
  • Summary en 2 líneas, business language
  • CVSS 3.1 propio con justificación de cada vector
  • Steps numerados, reproducibles desde cero
  • PoC video 60-90s + curl raw + screenshots
  • Impact statement con consecuencias de negocio (PII, GDPR, financial, reputational)
  • Remediation concreta (no "validar input" genérico)
  • Search de dupes en disclosed reports + Hacktivity
  • Cerré sesión, abrí incógnito, repetí mis steps — funciona
  • El bug está en scope (releí scope al final)
  • No mezclé múltiples bugs en un report

Labs relacionados

Practica vulnerabilidades reales para entrenar el PoC y la documentación con labs de bug bounty.

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta
Premium · 1 técnica más

Hay un payload extra al final

El template exacto de PoC video que multiplica por 3 la velocidad de triage — usado por top hunters en H1 con >$100k anuales.

Desbloquear

5 €/mes · cancela cuando quieras

Artículos relacionados