
Trova la vulnerabilità che i tuoi test non sono mai stati scritti per individuare. Una demo di ReGrade che modella CVE-2023-5968: individua una fuga di hash di password confrontando un'app con sé stessa.
Una demo pratica di scoperta di zero-day con ReGrade. Punterai una normale suite di test su ReGrade, la registrerai contro un piccolo servizio, la riprodurrai contro una seconda copia dello stesso servizio, e userai Claude Code + gli strumenti MCP di ReGrade per far emergere una perdita di hash di password — una vulnerabilità che nessun test è stato scritto per trovare.
Modella un bug reale: CVE-2023-5968, in cui l'endpoint di aggiornamento username di una piattaforma di collaborazione restituiva l'intero oggetto utente incluso l'hash bcrypt della password. Fu pubblicato nel 2017 e sopravvisse a 7 anni di test, revisioni e audit. (Il write-up di Curtail.)
Il colpo di scena: non esiste una v2. Confronti l'app con se stessa. Una nuova istanza genera hash delle
sue password con salt bcrypt diversi, quindi i valori dell'hash rilasciato differiscono tra le due copie —
ed è quell'entropia che ReGrade segnala. La vulnerabilità è latente nel codice che hai
già pubblicato; non serve alcun cambio di versione per trovarla.
regrade da https://app.regrade.curtail.com/downloads e imposta REGRADE_API_KEY
(o ~/.regrade/key).claude plugin marketplace add https://app.regrade.curtail.com/downloads/latest/marketplace.json
poi claude plugin install regrade@regrade --scope user, e collegalo una volta (/mcp,
accedendo con lo stesso account della tua chiave).Una piccola API di "chat di team" (app/store.py) con utenti e canali. Docker Compose esegue due
copie identiche — stessa immagine, stesso codice, nessun flag di versione:
http://localhost:8001 — registri contro questa.http://localhost:8002 — riproduci contro questa.Un endpoint ha un difetto volutamente inserito:
| Endpoint | Comportamento |
|---|---|
GET /users/<id> | — non restituisce mai la password. La baseline pulita. |
Le password sono hashate con bcrypt all'avvio, quindi instance-a e instance-b contengono hash diversi per lo stesso utente.
git clone https://github.com/Curtail-Inc/hello-ReGrade-security
cd hello-ReGrade-security
docker compose up -d --build
traffic/test_api.py è una normale suite di test funzionali: login, lettura di un utente, rinomina di un utente,
elenco dei canali. Verifica il comportamento CRUD e non fa alcuna asserzione di sicurezza — non controlla mai
se password fuoriesce. (Perché dovrebbe? Nessuno sapeva che il bug esistesse.)
Avvia il proxy sensore davanti a instance-a:
regrade proxy --target http://localhost:8001 --port 19870
In un altro terminale, esegui la stessa suite di test — basta puntare BASE_URL al proxy. Questa è
l'unica modifica:
BASE_URL=http://localhost:19870 python -m pytest traffic/test_api.py
Tutti i test passano, invariati. Ferma il proxy (Ctrl-C); la registrazione viene caricata e stampa un
Recording ID: <uuid> — prendine nota.
regrade replay --rec-id <RECORDING_ID> --target http://localhost:8002
Stesso codice su entrambi i lati — le uniche differenze sono i valori che una nuova istanza genera.
Apri questo repository in Claude Code e chiedigli di guidarti attraverso la riproduzione. Guidato dal
CLAUDE.md di questo repo, esso:
summarize_deltas → diversi delta: il token di login, i timestamp created_at dei canali
e — silenziosamente tra questi — $.password.create_id_mapping per il $.token della sessione (un ID dinamico, non rumore da scartare),create_filter_rule DROP per $.channels[*].created_at (un timestamp generato a ogni avvio),apply_profile_to_replay, poi query_deltas(unlabeled_only=true) — ripeti finché non rimane un solo
delta.$.password — un hash bcrypt nel corpo di una risposta.
Una perdita di classe CVE, trovata con zero conoscenze pregresse e zero asserzioni di sicurezza.Il token di sessione e l'hash della password entrambi differiscono tra le due esecuzioni — entrambi sono stringhe ad alta entropia che cambiano ogni volta. Uno è rumore legittimo che mappi; l'altro è una violazione. Non puoi distinguerli con "è cambiato" — devi guardare cosa è cambiato. Se filtrassi ogni campo ad alta entropia come rumore, avresti nascosto la vulnerabilità.
Questa è la lezione: ReGrade non valida aspettative, confronta comportamenti — così può far emergere i bug per cui nessuno ha pensato di scrivere un test.
app/store.py è un unico file. I percorsi GET chiamano sanitize(); il percorso PATCH se ne dimentica.
Guarda dopo averlo trovato con ReGrade — il punto è che ReGrade lo ha individuato dal solo traffico,
confrontando l'app con se stessa.
Apache-2.0.
PATCH /users/<id> (rename) | Il bug — restituisce l'intero oggetto utente incluso l'hash bcrypt della password. Una chiamata sanitize() mancante, esattamente come in CVE-2023-5968. |