[Bug]: DPoP replay markers grow without bound
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- Start a server environment that accepts DPoP-authenticated requests.
- Send valid DPoP requests with unique
jtivalues. - Inspect the configured secrets directory after each request.
- Separately, submit a token exchange with a valid DPoP proof and an invalid bootstrap credential.
Expected behavior
Replay state should remain atomic while being retained only for the proof acceptance window. A token exchange should validate its bootstrap credential before writing replay state.
Actual behavior
Each accepted proof creates a permanent dpop-proof-<digest>.bin file in the general secrets directory. Normal authenticated traffic adds one file per request, and no cleanup removes them. The token exchange path also records a valid proof before rejecting an invalid bootstrap credential, allowing file creation and fsync work without a usable credential.
Impact
Major degradation over long-running or high-traffic server lifetimes due to unbounded file and inode growth. The finding affects availability and reliability; no credential disclosure was identified.
Version or commit
main at 7963ac740
Investigation
Daybreak Blue confirmed the persistent allocation path and found that replay markers could also be lost across a partial bucket-boundary claim if writes were ordered incorrectly. Fable independently confirmed that normal DPoP traffic reproduces the unbounded growth and recommended a focused reliability fix with bounded, dedicated replay storage and credential preflight.
Proposed fix: #8845
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/server and reproduce accepted DPoP requests while inspecting the configured secrets directory. Trace replay-marker writes and the token-exchange credential check, then verify that replay state is bounded and atomic, retained only for the acceptance window, and not written before invalid bootstrap credentials are rejected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- authentication, backend, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100