| 1 | | Round-1 finding | Disposition | Rev-2 assessment | |
| 2 | |---|---|---| |
| 3 | | 1. Login CSRF | fixed | §5.1 requires a confirmation nonce and request-origin checks, including legacy confirmation. | |
| 4 | | 2. Unlimited guessing budgets | fixed | §5 adds shared online guessing limits and creates no redeemable challenge for refused requests. | |
| 5 | | 3. Pending-action hash mismatch | fixed | §6 specifies redemption by stored hash with the existing safeguards. | |
| 6 | | 4. SMTP fallback to Keymail | fixed | §4 adopts the settled B4 classification; §11 applies that policy to notifications. | |
| 7 | | 5. First CLI step-up email suppressed | fixed | §§5.3 and 7 implement B2: fresh email sign-in counts as step-up, with separate step-up send limits. | |
| 8 | | 6. Challenge outlives pending action | fixed | §6 gives step-up challenges the pending action’s ten-minute lifetime. | |
| 9 | | 7. Recipient validation | fixed | §11 requires normalized, strictly parsed bare addresses throughout. | |
| 10 | | 8. `next` bypasses onboarding | fixed | §8 requires account selection or creation before following `next`. | |
| 11 | | 9. Existing SES identity ownership | fixed | §9 explicitly requires the adoption check and ownership TXT record. | |
| 12 | |
| 13 | Reviewed spec rev 2 at `ac21aa3b`. These dispositions assess the design, not completed implementation. |
| 14 | |
| 15 | 1. **P1 — Read-only challenge-table access permits offline code recovery and account takeover.** |
| 16 | |
| 17 | **Spec:** §5, particularly [the hash definition and database-read guarantee](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/email-signin/docs/superpowers/specs/2026-10-21-console-email-signin-design.md:143). |
| 18 | |
| 19 | **Evidence:** [server.go:2733](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/email-signin/internal/console/server.go:2733) takes the target address from an unauthenticated requester. Existing session hashes protect a 32-byte random secret generated at [store.go:2394](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/email-signin/internal/console/store.go:2394); the proposed code hash instead protects six digits using an ID known to that requester. |
| 20 | |
| 21 | **Failure:** An attacker requests a challenge for the victim and retains their own challenge cookie. With read-only access to the resulting database row, they enumerate `sha256(id || code)` offline, then submit the recovered code once. Neither online guessing limit helps. An in-memory reproduction recovered a sample code in under one second. This violates the explicit database-read guarantee without requiring mailbox access. |
| 22 | |
| 23 | **Fix:** Authenticate the code digest with a server secret stored outside the database, such as HMAC over the challenge ID and code. Retain the online limits. |
| 24 | |
| 25 | 2. **P2 — The new guessing limit lets one browser invalidate another browser’s valid links.** |
| 26 | |
| 27 | **Spec:** [§5’s address-wide challenge deletion](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/email-signin/docs/superpowers/specs/2026-10-21-console-email-signin-design.md:167). |
| 28 | |
| 29 | **Evidence:** The request entry point at [server.go:2730](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/email-signin/internal/console/server.go:2730) requires no session or mailbox proof. The existing redemption precedent deletes only the presented token at [store.go:2486](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/email-signin/internal/console/store.go:2486); rev 2 explicitly expands deletion to every live sign-in challenge for the address. |
| 30 | |
| 31 | **Failure:** An attacker creates challenges for a victim in attacker-controlled browsers and exhausts the shared wrong-code budget. That burns a legitimate link already delivered to the victim’s separate browser, despite the attacker never possessing that link. Three challenge requests, spaced to respect the cooldown, suffice to exceed ten wrong guesses. |
| 32 | |
| 33 | **Fix:** Keep the shared code-verification limit, but preserve other browsers’ high-entropy links. Burn only the offending challenge; allow existing valid links to redeem while code verification is throttled. |
| 34 | |
| 35 | No files were edited. No repository test suites were run. |