{"id":"sec-dev-threat-model-password-reset","audience":"developers","category":"security","track":"security","technique":"grounding","title":"List the threats in a password reset design","free":false,"task":"Before the design review, list threats for this password reset spec. Write exactly 4 numbered lines like '1. (step 2) Threat: ... | Mitigation: ...', each starting with the spec step it comes from. Don't list protections the spec already has as missing. Plain text, under 150 words.","materialLabel":"Design spec (attached to your prompt automatically)","material":"Design spec: Password reset v2 (Owner: Sana, team Accounts)\n\nFlow:\n1. User enters their email on /forgot. The page always shows \"If that account exists, we sent a link\" (same message either way).\n2. Server creates a reset token: the user's ID plus the current Unix time, base64 encoded.\n3. Email contains https://app.example.com/reset?token=<token>.\n4. The token does not expire. It is stored in the users table in plain text.\n5. When the link is used, the user sets a new password. Existing sessions on other devices stay logged in.\n6. Rate limit: 5 reset requests per email per hour, and 20 per IP per hour (already built, in the API gateway).\n7. The reset page loads analytics from a third-party script, and the full URL (with token) is sent to analytics as the page view.\n\nOut of scope for v2: SMS reset, account recovery for users who lost access to their email.","rules":[{"type":"numberedItems","count":4},{"type":"plainText"},{"type":"maxWords","max":150}],"mistakes":[{"title":"A generic checklist","why":"The AI lists OWASP-style threats like XSS and CSRF that aren't tied to this design.","fix":"Say: \"Start each line with the spec step it comes from, like (step 2).\"","checks":["r0","r1"]},{"title":"Flagging what's already built","why":"The AI recommends rate limiting even though the spec has it.","fix":"Add: \"Don't list protections the spec already has.\"","checks":["r2"]},{"title":"No shape","why":"The AI writes a long threat model with STRIDE headings.","fix":"Show it: \"Exactly 4 lines: Threat: ... | Mitigation: ...\"","checks":["numberedItems","plainText"]},{"title":"Trusting the AI to count words","why":"AI is bad at counting. Ask for \"under 120 words\" and it often lands well over.","fix":"Ask for less than the limit and cap each line: \"each line under 15 words, under 90 words total.\"","checks":["maxWords"]}],"promptHints":[{"label":"Ties threats to the spec","patterns":["spec","specific","tied to","this design"]},{"label":"Skips existing protections","patterns":["already (has|have|built)","existing","rate limit","don'?t list"]},{"label":"Shows the line shape","patterns":["threat:","mitigation","\\(step"]},{"label":"Says exactly how many","patterns":["\\b4\\b.{0,25}(line|threat|item)","exactly (4|four)"]},{"label":"Sets a word limit","patterns":["\\d+\\s*words","word (limit|count)"]}],"hint":"A useful threat model is about this design, not every possible attack. Tell the AI to tie each threat to the spec and skip what's already built.","rubricLabels":["Covers the guessable token (user ID plus timestamp, base64) with a mitigation of a long random token, plus at least two of: tokens never expire or are stored in plain text, other sessions stay logged in, the token leaking to third-party analytics","Every line starts with the spec step it comes from in parentheses, like '(step 2)', followed by 'Threat:' and '| Mitigation:'","Does not say rate limiting or the same-message account check is missing, and does not list SMS reset or email account recovery as threats"]}