HarperFast / HarperFast/harper
Commit-retry TOCTOU: authorized writes are not re-authorized when a conflict retry re-runs commit against a changed record
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
Split out of [#1842 (Record-scoped write authorization)](https://github.com/HarperFast/harper/pull/1842)'s cross-model review — a pre-existing gap across ALL authorization (single-record and record-scoped alike), not introduced or widened there.
## The gap
`allow*` hooks run before writes are staged, but optimistic-conflict handling re-runs write `commit` callbacks against the then-current entry (`DatabaseTransaction` retry; e.g. `Table.ts` `_writeDelete`'s `commit(txnTime, existingEntry, retry, ...)`). Sequence:
1. User A passes `allowUpdate`/`allowDelete` for a record they own.
2. A concurrent transaction changes the row's ownership to B and commits first.
3. The retry applies A's already-authorized write to B's version — no re-authorization.
Async hooks can't be re-run inside the synchronous commit handlers, so re-checking in place isn't an option.
## Direction (from the review)
Mark authorization-sensitive writes (those staged under an armed `checkPermission`) as non-retryable on conflict: abort, surface a conflict error, and let the outer request re-load and re-authorize. Needs care not to regress throughput for the internal/replication paths that never carry authorization.
Generated by KrAIs (Claude Fable 5) during #1842's review adjudication.
Contributor guide
Research direction
Trace DatabaseTransaction conflict retries and Table.ts _writeDelete, especially the commit path and armed checkPermission state. Verify how authorized writes are marked and how internal or replication writes bypass authorization. Done means authorization-sensitive writes abort on conflict for the outer request to reload and re-authorize, without making unauthorized paths non-retryable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- authorization, backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100