Summary
frontend/taskdeck-web/src/store/permissionsStore.ts commits board-access reads independently of grant/update/revoke settlements. An older read can therefore overwrite a newer confirmed mutation in the client cache.
This is a source-traced audit finding on main 307c3b8b50bec1cb0bfaea3e570a942bcb1d4451. It has not yet been reproduced in the canonical Vue/Pinia test environment, so implementation must begin with failing real-store regressions.
Reachable races
Revoke
- Start a deferred board-access read whose payload contains entry X.
- Successfully revoke X and remove it from the local collection.
- Resolve the older read with its original payload.
- The stale read can reintroduce X in the UI.
Role update
An older list carrying role R1 can settle after a successful update to R2 and replace the confirmed role with R1.
The store also exposes shared loading/error state that whichever overlapping operation settles first can clear or replace, regardless of which operation still owns visible work.
Expected contract
- Establish per-board read ownership and a mutation revision/epoch so a read begun before a confirmed mutation cannot overwrite it.
- Scope success, error and loading settlement to the operation that owns them.
- Preserve valid concurrency across independent boards.
- Inspect and contract the identity/reset lifecycle before claiming logout/relogin protection.
- Treat cached roles as UI state only; server-side authorization remains authoritative.
Acceptance
- Deferred real Pinia regression for read → revoke → old read settlement.
- Equivalent role-update and grant interactions.
- Competing-read ordering, stale failure and loading/error ownership coverage.
- Old request settling after identity reset/logout and after login as another session, including same user ID where relevant.
- Independent-board operations remain concurrent.
- Existing server authorization and demo-mode refusal semantics remain unchanged.
- Frontend lint, typecheck, build, full Vitest and exact-head hosted CI pass.
Security boundary
This finding concerns truthful client state. It does not demonstrate a server authorization bypass or prove that no external identity cleanup currently exists.
Audit provenance
Found during the 2026-09-21 recent-development/state-ownership audit. Searches for open issues naming permissionsStore.ts or this read-versus-mutation sequence found no matching defect issue.
Summary
frontend/taskdeck-web/src/store/permissionsStore.tscommits board-access reads independently of grant/update/revoke settlements. An older read can therefore overwrite a newer confirmed mutation in the client cache.This is a source-traced audit finding on main
307c3b8b50bec1cb0bfaea3e570a942bcb1d4451. It has not yet been reproduced in the canonical Vue/Pinia test environment, so implementation must begin with failing real-store regressions.Reachable races
Revoke
Role update
An older list carrying role R1 can settle after a successful update to R2 and replace the confirmed role with R1.
The store also exposes shared loading/error state that whichever overlapping operation settles first can clear or replace, regardless of which operation still owns visible work.
Expected contract
Acceptance
Security boundary
This finding concerns truthful client state. It does not demonstrate a server authorization bypass or prove that no external identity cleanup currently exists.
Audit provenance
Found during the 2026-09-21 recent-development/state-ownership audit. Searches for open issues naming
permissionsStore.tsor this read-versus-mutation sequence found no matching defect issue.