From 29fb9089324e2da78de0aff2e02fca7bc7753d23 Mon Sep 17 00:00:00 2001 From: null Date: Mon, 17 Aug 2026 22:53:53 -0500 Subject: [PATCH] feat(qa): pass H, authorization and abuse The passes stopped at G, and A-G share an assumption that hides an entire class of defect: every one of them asks a legitimate user to do legitimate things. Nothing looked at what happens when the caller is not who they claim, does not own what they ask for, or asks too often. That assumption has already cost this portfolio once. requireCoupleContext in Closer-Couples never verified the caller belonged to the couple whose data was returned -- authentication present, correct, and proving nothing about ownership. No pass A-G would have found it. Pass H covers six cases: authenticated endpoints called logged-out, a list endpoint checked for rows the caller should not see, User A requesting User B's object by id, a privileged route opened as an ordinary user, the expensive endpoint hit repeatedly, and the built bundle and localStorage inspected. The organising sentence, which is the reason it is a separate pass rather than more rows in B: authenticated is not the same as owning, and neither is the same as permitted. closes #2 Co-Authored-By: Claude Opus 5 (1M context) --- docs/qa/ClaudeQACoverage.md | 1 + docs/qa/ClaudeQAPlan.md | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/docs/qa/ClaudeQACoverage.md b/docs/qa/ClaudeQACoverage.md index c8d9c76..723d53d 100644 --- a/docs/qa/ClaudeQACoverage.md +++ b/docs/qa/ClaudeQACoverage.md @@ -23,6 +23,7 @@ Review trigger: Any QA round run | E — End of loop | **Blocked** | | | F — Accessibility | Not run | | | G — Performance | Pass | | +| H — Authorization and abuse | Not run | | ## Standing gaps diff --git a/docs/qa/ClaudeQAPlan.md b/docs/qa/ClaudeQAPlan.md index c6fb459..c8e5366 100644 --- a/docs/qa/ClaudeQAPlan.md +++ b/docs/qa/ClaudeQAPlan.md @@ -33,10 +33,28 @@ skipped one is visible. | E | The end of the loop — the state that is hardest to reach on purpose | | F | Accessibility: keyboard only, screen reader labels, contrast, text scaling | | G | Performance under the load this product will actually see | +| H | Authorization and abuse: every authenticated endpoint called logged-out; a list endpoint checked for rows the caller should not see; User A requesting User B's object by id; a privileged route opened as an ordinary user; the most expensive endpoint hit repeatedly; the built bundle and `localStorage` inspected for anything secret | +### Why H is separate from B + +**Authenticated is not the same as owning, and neither is the same as +permitted.** Login is the front door; every room inside still needs its own +lock. Pass B walks the flow as a real user, which means it walks it as a user +who is entitled to everything it touches — so B cannot see the entire class of +defect where the entitlement was never checked. + +This has already cost this portfolio once. `requireCoupleContext` never verified +that the caller belonged to the couple whose data was being returned: +authentication was present, correct, and proved nothing. No pass A-G would have +looked for it, because every one of them asks a legitimate user to do legitimate +things. + +Run H as somebody who is not entitled: logged out, logged in as the wrong +person, and logged in as the right person asking too often. + ## What counts as a finding A finding needs: what was done, what happened, what should have happened, and