Encuentra la vulnerabilidad que tus pruebas nunca se escribieron para detectar. Una demo de ReGrade que modela CVE-2023-5968: detecta una fuga de hash de contraseña comparando una aplicación consigo misma.
Una demostración práctica de descubrimiento de vulnerabilidades de día cero con ReGrade. Apuntarás una suite de pruebas ordinaria a ReGrade, la grabarás contra un pequeño servicio, la reproducirás contra una segunda copia del mismo servicio, y usarás Claude Code + las herramientas MCP de ReGrade para revelar una fuga de hash de contraseña — una vulnerabilidad que ningún test fue escrito para encontrar.
Modela un bug real: CVE-2023-5968, donde el endpoint de actualización de nombre de usuario de una plataforma de colaboración devolvía el objeto de usuario completo incluyendo el hash bcrypt de la contraseña. Se publicó en 2017 y sobrevivió 7 años de tests, revisiones y auditorías. (El artículo de Curtail.)
El giro: no hay v2. Comparas la aplicación consigo misma. Una instancia nueva hashea
sus contraseñas con sales bcrypt diferentes, por lo que los valores del hash filtrado difieren entre las
dos copias — y esa entropía es lo que ReGrade señala. La vulnerabilidad es latente en el código que
ya enviaste; no se necesita ningún cambio de versión para encontrarla.
regrade desde , y establece
(o ).REGRADE_API_KEY~/.regrade/keyclaude plugin marketplace add https://app.regrade.curtail.com/downloads/latest/marketplace.json
luego claude plugin install regrade@regrade --scope user, y conéctalo una vez (/mcp,
con la sesión iniciada en la misma cuenta que tu clave).Una pequeña API "chat de equipo" (app/store.py) con usuarios y canales. Docker Compose ejecuta dos
copias idénticas — misma imagen, mismo código, sin indicador de versión:
http://localhost:8001 — grabas contra esta.http://localhost:8002 — reproduces contra esta.Un endpoint tiene una falla plantada:
| Endpoint | Comportamiento |
|---|---|
GET /users/<id> | Sanitizado — nunca devuelve la contraseña. La línea base limpia. |
PATCH /users/<id> (renombrar) | El bug — devuelve el objeto de usuario completo incluyendo el hash bcrypt de password. Una llamada sanitize() que falta, exactamente como CVE-2023-5968. |
Las contraseñas se hashean con bcrypt al arrancar, por lo que instance-a e instance-b contienen hashes diferentes para el mismo usuario.
git clone https://github.com/Curtail-Inc/hello-ReGrade-security
cd hello-ReGrade-security
docker compose up -d --build
traffic/test_api.py es una suite de pruebas funcionales normal: inicio de sesión, lectura de un usuario, renombrado de un usuario,
listado de canales. Verifica el comportamiento CRUD y no hace ninguna aserción de seguridad — nunca comprueba
si password se filtra. (¿Por qué iba a hacerlo? Nadie sabía que el bug existía.)
Inicia el proxy sensor delante de instance-a:
regrade proxy --target http://localhost:8001 --port 19870
En otra terminal, ejecuta la misma suite de pruebas — solo apunta BASE_URL al proxy. Esto es
el único cambio:
BASE_URL=http://localhost:19870 python -m pytest traffic/test_api.py
Todos los tests pasan, sin cambios. Detén el proxy (Ctrl-C); la grabación se sube e imprime un
Recording ID: <uuid> — anótalo.
regrade replay --rec-id <RECORDING_ID> --target http://localhost:8002
El mismo código en ambos lados — las únicas diferencias son los valores que genera una instancia nueva.
Abre este repositorio en Claude Code y pídele que te guíe a través de la reproducción. Guiado por el
CLAUDE.md de este repositorio, hará lo siguiente:
summarize_deltas → varios deltas: el token de inicio de sesión, las marcas de tiempo created_at de los canales,
y — silenciosamente entre ellos — $.password.create_id_mapping para el $.token de la sesión (un ID dinámico, no ruido que descartar),create_filter_rule DROP para $.channels[*].created_at (una marca de tiempo por arranque),apply_profile_to_replay, luego query_deltas(unlabeled_only=true) — repite hasta que solo
quede un delta.$.password — un hash bcrypt en el cuerpo de una respuesta.
Una fuga de clase CVE, encontrada con cero conocimiento previo y cero aserciones de seguridad.El token de sesión y el hash de la contraseña ambos difieren entre las dos ejecuciones — ambos son cadenas de alta entropía que cambian cada vez. Uno es ruido legítimo que mapeas; el otro es una brecha. No puedes distinguirlos por "ha cambiado" — tienes que mirar qué ha cambiado. Si filtraras cada campo de alta entropía como ruido, habrías ocultado la vulnerabilidad.
Esa es la lección: ReGrade no valida expectativas, compara comportamiento — por lo que puede sacar a la luz los bugs que a nadie se le ocurrió escribir un test para detectar.
app/store.py es un solo archivo. Las rutas GET llaman a sanitize(); la ruta PATCH se olvida de hacerlo.
Mira después de haberlo encontrado con ReGrade — el punto es que ReGrade lo detectó solo a partir del tráfico
solo, comparando la aplicación consigo misma.
Apache-2.0.