Security hardening: tus uploads are not bound to the user who created them #491
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Cordy/Cairn#491
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Status: from source (read at
bd006ef, not reproduced). The affected code is unchanged onmain(e1c855d).What happens
HEAD,PATCHandDELETEon/api/v1/tus/{id}look an upload up by id only — there is no owner check.finalizewritesu.Targetthroughh.Store.Write(r.Context(), …)(internal/tus/tus.go:226–233), i.e. in the storage scope of whoever sends the completing PATCH, not the user who created the upload. With per-user homes, another authenticated user who knows an upload id can:Mitigating factor
Ids come from
crypto/rand(internal/tus/tus.go:309), so this needs a leaked id (proxy or access logs, a shared machine, a client bug). Hence "hardening" rather than an open hole.Suggested fix
Record the creating user at
POST; answer404to any other user onHEAD/PATCH/DELETE; always finalize in the creator's scope. Add a two-user test.Found while building the cairn-desktop tus client (phase 2, Cordy/cairn-desktop#24/#29). Filed by Claude on behalf of @Cordy.
Fixed in v0.6.166 (PR #501, live on the dogfood).
As suggested: the creating user is recorded in the upload sidecar at
POST;HEAD,PATCHandDELETEfrom any other user answer the same 404 as an unknown id (no existence oracle), and because only the owner can send the completing PATCH, finalize always runs in the creator's storage scope. Two-user test added (foreign HEAD/PATCH/DELETE all 404, owner still completes), witnessed red first.Migration note: sidecars written before this release carry no owner and become inert — no authenticated user resolves to the empty owner, so nobody can claim, append to, or terminate them. They cost a few spool bytes until removed by hand; clients simply restart those uploads. (An automatic boot purge was considered and dropped: unauthenticated restart recovery — exercised by the test suite — must keep working, and inert-but-present is equally safe.)