From ab968565ecd332e337c518f71e06b881539cf4b2 Mon Sep 17 00:00:00 2001 From: wshallwshall Date: Wed, 12 Aug 2026 19:26:27 -0500 Subject: [PATCH] backlog: amend #1131 -- an administrative unlock DOES ship, and the regex that missed it could never have found it Reported by the ASVS tracking lane after a builder found three things they had not. All four load-bearing claims verified here against origin/main, not relayed. 1. THE REMEDY IS STRONGER THAN THE ITEM CREDITS. auth_routes.py:753 routes POST /users/{user_id}/reset-password and :757 takes Depends(require_step_up(Permission.USERS_MANAGE)) -- the admin RE-AUTHENTICATES. That matters because #1131's own research question says an unlock route is "a candidate with its own abuse surface, not an answer", and a step-up is a partial answer to exactly that surface. Coverage is uniform: locked_until=NULL in all three backends, two sites each, so this is not a partial-surface finding. 2. THE :1474 CITATION IS STALE. At 9d98f339 that line is an unrelated AD row; the disputed parenthetical is at :1544. Cite the greppable phrase, not the line. 3. THE METHOD DEFECT, which is the part worth keeping. The filed absence claim searched `def admin_unlock|unlock_account|clear_lockout`. Measured: 0 hits in auth/service.py, a file containing exactly 1 `def admin_reset_password`. THE REGEX CANNOT STRUCTURALLY MATCH THE THING THAT SHIPS. The zero was a true answer to a question nobody asked, and the conclusion "no dedicated administrative unlock exists" is literally true and materially misleading -- an unlock ships, as a side effect of a forced password rotation. PRESCRIPTION, recorded in the item: an absence claim over a CAPABILITY must be written from the STATE, not from plausible function names. "Find every write to locked_until" would have found it; "find every function called something-unlock" never could. The item STAYS OPEN and its question hardens: the adequacy and disclosure of a step-up-gated forced-rotation reset as a remedy for a MALICIOUS lockout, rather than whether an unlock affordance exists. Closing it on the route's existence would answer the easy question and drop the one worth researching. Worth naming: this is the same defect family as the day's other measurement errors -- an instrument that cannot see the class it certifies -- but it is the first instance found INSIDE A BACKLOG ITEM'S OWN EVIDENCE rather than in tooling. --- docs/BACKLOG.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 0e068a53..72254ae0 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -6323,9 +6323,21 @@ filing. ## 1131. research an honest pass for ASVS 6.1.1 -- what the anti-automation documentation must say about malicious account lockout > 🔢 **Filed 2026-08-08 - not started. RESEARCH item: the goal is an HONEST pass, and "cannot honestly reach pass" is a valid finding.** Value **7/10** · Difficulty **5/10**. ASVS **6.1.1** (L1) currently scores **partial**. The pinned verb asks that application documentation make clear how the anti-automation controls are configured and prevent malicious account lockout. One parenthetical at `docs/SECURITY.md:1474` answers the lockout clause, and its claim does not survive the shipped serial re-lock at `messagefoundry/auth/service.py:665-668`. +> +> ⚠️ **AMENDED 2026-08-13 -- THE ITEM STAYS OPEN AND ITS QUESTION IS RE-SCOPED. Three corrections, and the third is the one worth reading.** +> +> **1. THE REMEDY IS STRONGER THAN THIS ITEM CREDITS, AND THE DIFFERENCE IS LOAD-BEARING.** `api/auth_routes.py:753` routes `POST /users/{user_id}/reset-password`, and `:757` takes `Depends(require_step_up(Permission.USERS_MANAGE))` -- **the admin RE-AUTHENTICATES; it is not a plain permission check.** This item's own research question says *"anything that clears a lock is itself a control an attacker wants, so an unlock route is a candidate with its own abuse surface, not an answer"* -- and the step-up is a **partial answer to exactly that abuse surface**, which nothing in the record credits. Coverage is uniform, so this is not a partial-surface finding: all three backends clear the lock in `set_password` (`store.py`, `postgres.py`, `sqlserver.py` -- `failed_attempts=0`, `locked_until=NULL`, two sites each). +> +> **2. THE `docs/SECURITY.md:1474` CITATION IS STALE and will cost the next reader time.** At engine `9d98f339` that line is an unrelated **AD** row in the comparative-properties table. The disputed parenthetical is now at **`:1544`**, in the three-limiter anti-automation table. **Cite the greppable phrase, not the line number.** +> +> **3. WHY THIS ITEM GOT IT WRONG -- RECORDED AS METHOD, NOT MERELY AS A CORRECTION.** The filed absence claim searched `def admin_unlock|unlock_account|clear_lockout`. Measured on `main`: that regex returns **0 hits** in `auth/service.py`, a file containing exactly **1** `def admin_reset_password`. **The regex CANNOT STRUCTURALLY MATCH THE THING THAT SHIPS.** So the zero was a **true answer to a question nobody asked**, and this item's conclusion -- *"no dedicated administrative unlock exists"* -- is **literally true and materially misleading**: an unlock ships, as a side effect of a forced password rotation. +> +> > **THE PRESCRIPTION: an absence claim over a CAPABILITY must be written from the STATE, not from plausible function names.** *"Find every write to `locked_until`"* would have found it; *"find every function called something-unlock"* never could. +> +> **RE-SCOPE:** the live question is the **adequacy and disclosure of a step-up-gated forced-rotation reset as a remedy for a MALICIOUS lockout** -- not whether an unlock affordance exists. That is a harder question than the one filed, and it is why this stays open rather than closing on the route's existence. **Cluster:** Security / ASVS remediation research. **Priority:** P1. **Verdict:** research. -**Severity:** no product effect on the control itself; on a first deployment an operator reading the documented protection set would not learn that a known local username can be held refused by repetition at roughly five requests per fifteen minutes, nor that no dedicated administrative unlock exists. +**Severity:** no product effect on the control itself; on a first deployment an operator reading the documented protection set would not learn that a known local username can be held refused by repetition at roughly five requests per fifteen minutes, ~~nor that no dedicated administrative unlock exists.~~ **[STRUCK -- an unlock DOES ship, step-up-gated, via forced password rotation; see the 2026-08-13 amendment above.]** **The pinned verb.** "The documentation must make clear how these controls are configured and prevent malicious account lockout."