Skip to content

fix(#401): Security: file-request visitor places unbounded files when no file limit is set - #410

Merged
BeSovereign merged 1 commit into
mainfrom
fix/issue-401
Oct 20, 2026
Merged

BeSovereign merged 1 commit into
mainfrom
fix/issue-401

Conversation

@BeSovereign

@BeSovereign BeSovereign commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Refs #401

Bounded files per file request (1000 ceiling, 100 per visitor, counted placed plus open) and rate-limited visitor upload creation (60/min per request+visitor and per address); now also LocalBackend.dropUpload deletes a visitor's unplaced file_request_uploads row together with its dropped upload (SIZE_MISMATCH overrun, expiry), and migration 032 removes such orphans, so overrunning uploads can no longer grow the table without bound. Adversarial and test-adversary reviews ran; the test adversary's blocking gap (the cloud-placed row's placed_at guard) is now pinned by the cloud test, and the PATCH ceiling and German hint wording were fixed.

Driver gates (measured, not claimed)

  • Suites: typecheck: 1 passed, 0 failed | lint: 1 passed, 0 failed | unit: 1186 passed, 0 failed | e2e: 603 passed, 0 failed
  • Red/green check on declared tests: server/test/fileRequests.test.ts, server/test/db.test.ts, e2e/file-requests.spec.ts
red/green output
RED without the change:
sit-8e267-again-and-again-it-says-why-mobile-chrome/trace.zip

    ────────────────────────────────────────────────────────────────────────────────────────────────

  4 failed
    [desktop-chrome] › e2e/file-requests.spec.ts:189:1 › #401: a request without a file limit shows the ceiling to the owner and the files left to the visitor 
    [desktop-chrome] › e2e/file-requests.spec.ts:215:1 › #401: a visitor's page waits out the creation rate limit; refused again and again, it says why 
    [mobile-chrome] › e2e/file-requests.spec.ts:189:1 › #401: a request without a file limit shows the ceiling to the owner and the files left to the visitor 
    [mobile-chrome] › e2e/file-requests.spec.ts:215:1 › #401: a visitor's page waits out the creation rate limit; refused again and again, it says why 


GREEN with the change:
 chunk size limit for this warning via build.chunkSizeWarningLimit.
$ node build.mjs


Running 4 tests using 1 worker

  ✓  1 [desktop-chrome] › e2e/file-requests.spec.ts:189:1 › #401: a request without a file limit shows the ceiling to the owner and the files left to the visitor (913ms)
  ✓  2 [desktop-chrome] › e2e/file-requests.spec.ts:215:1 › #401: a visitor's page waits out the creation rate limit; refused again and again, it says why (7.2s)
  ✓  3 [mobile-chrome] › e2e/file-requests.spec.ts:189:1 › #401: a request without a file limit shows the ceiling to the owner and the files left to the visitor (1.0s)
  ✓  4 [mobile-chrome] › e2e/file-requests.spec.ts:215:1 › #401: a visitor's page waits out the creation rate limit; refused again and again, it says why (7.3s)

  4 passed (18.8s)

🤖 Generated with Claude Code

Bounded files per file request (1000 ceiling, 100 per visitor, counted placed plus open) and rate-limited visitor upload creation (60/min per request+visitor and per address); now also LocalBackend.dropUpload deletes a visitor's unplaced file_request_uploads row together with its dropped upload (SIZE_MISMATCH overrun, expiry), and migration 032 removes such orphans, so overrunning uploads can no longer grow the table without bound. Adversarial and test-adversary reviews ran; the test adversary's blocking gap (the cloud-placed row's placed_at guard) is now pinned by the cloud test, and the PATCH ceiling and German hint wording were fixed.

Refs #401

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BeSovereign

Copy link
Copy Markdown
Contributor Author

Security review (claude-fable-5-1): no blocking finding. Caps and rate limit are enforced atomically and synchronously, visitor ids are signed, address folding only tightens, no orphan rows, tests flip when each check is removed. Non-blocking: per-visitor cap is cookie-keyed by design; a request can be griefed to its 1000 ceiling with empty files and placed rows never free up; password limiter keys raw req.ip unlike the creation limiter; /info has no rate limit (pre-existing).

@BeSovereign
BeSovereign merged commit 3202fe3 into main Oct 20, 2026
3 checks passed
@BeSovereign
BeSovereign deleted the fix/issue-401 branch October 20, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant