carlos / platform Public
| Round-1 finding | Disposition | Rev-2 assessment | |---|---|---| | 1. Login CSRF | fixed | §5.1 requires a confirmation nonce and request-origin checks, including legacy confirmation. | | 2. Unlimited guessing budgets | fixed | §5 adds shared online guessing limits and creates no redeemable challenge for refused requests. | | 3. Pending-action hash mismatch | fixed | §6 specifies redemption by stored hash with the existing safeguards. | | 4. SMTP fallback to Keymail | fixed | §4 adopts the settled B4 classification; §11 applies that policy to notifications. | | 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. | | 6. Challenge outlives pending action | fixed | §6 gives step-up challenges the pending action’s ten-minute lifetime. | | 7. Recipient validation | fixed | §11 requires normalized, strictly parsed bare addresses throughout. | | 8. next bypasses onboarding | fixed | §8 requires account selection or creation before following next. | | 9. Existing SES identity ownership | fixed | §9 explicitly requires the adoption check and ownership TXT record. |
Reviewed spec rev 2 at ac21aa3b. These dispositions assess the design, not completed implementation.
- P1 — Read-only challenge-table access permits offline code recovery and account takeover.
Spec: §5, particularly the hash definition and database-read guarantee.
Evidence: 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; the proposed code hash instead protects six digits using an ID known to that requester.
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.
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.
- P2 — The new guessing limit lets one browser invalidate another browser’s valid links.
Spec: §5’s address-wide challenge deletion.
Evidence: The request entry point at server.go:2730 requires no session or mailbox proof. The existing redemption precedent deletes only the presented token at store.go:2486; rev 2 explicitly expands deletion to every live sign-in challenge for the address.
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.
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.
No files were edited. No repository test suites were run.