Labels: security, bug, infra, priority:critical
File: infra/contribution-worker/worker.js:68 (route), :139/:175 (body-trusted contributor_id), initiateRevoke/executeR2Purge (~:456/:607), lazy-progress GET :70
Description. The router wraps /admin/* routes in adminAuth (lines 55, 57, 59, 76) but POST /v1/revoke/cascade (line 68) has no auth and reads contributor_id straight from the request body. Anyone on the internet can revoke and purge any contributor.
Why it matters. POST /v1/revoke/cascade {"contributor_id":"<victim>","scope":"all"} sets the victim's revoked_at (permanent upload lockout) and enqueues a purge that deletes every R2 object under {free,pro,enterprise}-contributors/<victim>/. The cascade "lazily progresses" on unauthenticated GET /v1/revoke/cascade-status/<id>, so the attacker drives deletion to completion without waiting for cron. initiateRevoke will INSERT a non-existent contributor row, so IDs can be pre-revoked before a real user onboards. Irreversible, unauthenticated destruction of other users' data.
Tasks.
Dedup. No open issue/PR touches contribution-worker revoke auth. (PR #236 only renames workers + adds a version field; #233 removes outreach/launch.)
Labels:
security,bug,infra,priority:criticalFile:
infra/contribution-worker/worker.js:68(route),:139/:175(body-trustedcontributor_id),initiateRevoke/executeR2Purge(~:456/:607), lazy-progress GET:70Description. The router wraps
/admin/*routes inadminAuth(lines 55, 57, 59, 76) butPOST /v1/revoke/cascade(line 68) has no auth and readscontributor_idstraight from the request body. Anyone on the internet can revoke and purge any contributor.Why it matters.
POST /v1/revoke/cascade {"contributor_id":"<victim>","scope":"all"}sets the victim'srevoked_at(permanent upload lockout) and enqueues a purge that deletes every R2 object under{free,pro,enterprise}-contributors/<victim>/. The cascade "lazily progresses" on unauthenticatedGET /v1/revoke/cascade-status/<id>, so the attacker drives deletion to completion without waiting for cron.initiateRevokewillINSERTa non-existent contributor row, so IDs can be pre-revoked before a real user onboards. Irreversible, unauthenticated destruction of other users' data.Tasks.
contributor_idfor destructive actions; scope to an authenticated principal.Dedup. No open issue/PR touches contribution-worker revoke auth. (PR #236 only renames workers + adds a version field; #233 removes outreach/launch.)