[LOW] Deletion token accepted in the URL (?token=), leaking a bearer secret into logs/history #143

Closed
opened 2026-09-10 03:48:56 +00:00 by fen · 2 comments
Collaborator

handleDeletePaste accepts the deletion token via ?token= and the paste view JS fetches /api/pastes/{id}/redeem?token=. URL-carried bearer tokens end up in Traefik access logs and browser history; anyone with log access can delete/redeem the paste. Lower impact than an admin key since scope is one paste, but the same class of issue.

Repro

1. Create paste, note deletion_token T and id I.
2. curl -sk -X DELETE "https://palette-dev.archfox.org/api/pastes/$I?token=$T" -> 200 soft-deleted; token now sits in access logs
Expected: header-based token only, or a short-lived one-time URL token.
Actual: long-lived bearer secret accepted in URL.

Found during exploratory security/bug pass on palette-dev (2026-09-09). Reporting only, no fix attached.

handleDeletePaste accepts the deletion token via ?token= and the paste view JS fetches /api/pastes/{id}/redeem?token=. URL-carried bearer tokens end up in Traefik access logs and browser history; anyone with log access can delete/redeem the paste. Lower impact than an admin key since scope is one paste, but the same class of issue. ### Repro ``` 1. Create paste, note deletion_token T and id I. 2. curl -sk -X DELETE "https://palette-dev.archfox.org/api/pastes/$I?token=$T" -> 200 soft-deleted; token now sits in access logs Expected: header-based token only, or a short-lived one-time URL token. Actual: long-lived bearer secret accepted in URL. ``` Found during exploratory security/bug pass on palette-dev (2026-09-09). Reporting only, no fix attached.
fen added spent time 5 seconds 2026-09-10 03:49:08 +00:00
fen added the Low label 2026-09-10 03:49:49 +00:00
Author
Collaborator

Fix proposal: accept the deletion token only in the X-Deletion-Token header (and in the POST body of the UI flow), remove the ?token= query path, and redirect-strip tokens from URLs. One-file change in the deletion handler plus template updates.

Fix proposal: accept the deletion token only in the X-Deletion-Token header (and in the POST body of the UI flow), remove the ?token= query path, and redirect-strip tokens from URLs. One-file change in the deletion handler plus template updates.
fen added spent time 5 seconds 2026-09-10 13:18:19 +00:00
fen added the In Progress label 2026-09-10 13:18:20 +00:00
fen added QA and removed In ProgressLow labels 2026-09-10 13:24:32 +00:00
fen added spent time 10 seconds 2026-09-10 13:24:32 +00:00
fen added spent time 25 seconds 2026-09-10 13:36:58 +00:00
fen closed this issue 2026-09-10 13:38:15 +00:00
Author
Collaborator

QA passed on live palette-dev (image @sha256:813958aa..., merge commit fe75dfc on dev).

  • Create flow sets short-lived HttpOnly tok_ cookie (60s); no deletion token appears in any URL (created banner flow verified via cookie; grep token= in rendered page = 0).
  • DELETE /api/pastes/{id}?token= -> 403, paste survives; DELETE /api/pastes/{id}/redeem?token= -> 400, paste survives.
  • Authorization: Bearer header delete -> 200 soft-delete, redeem -> 200 hard delete, both confirmed live.
  • Rendered paste view (creator cookie) shows the danger delete button wired to sessionStorage deletion_token_ + header-based redeem.

Note: QA found the PR initially never SET the tok_ cookie (read-only in web.go), which would have broken the one-time created-banner token display; fixed on the branch (commit 00aaafe) with tests before merge.

Closing, branch deleted.

QA passed on live palette-dev (image @sha256:813958aa..., merge commit fe75dfc on dev). - Create flow sets short-lived HttpOnly tok_<id> cookie (60s); no deletion token appears in any URL (created banner flow verified via cookie; grep token= in rendered page = 0). - DELETE /api/pastes/{id}?token=<correct token> -> 403, paste survives; DELETE /api/pastes/{id}/redeem?token= -> 400, paste survives. - Authorization: Bearer header delete -> 200 soft-delete, redeem -> 200 hard delete, both confirmed live. - Rendered paste view (creator cookie) shows the danger delete button wired to sessionStorage deletion_token_<id> + header-based redeem. Note: QA found the PR initially never SET the tok_<id> cookie (read-only in web.go), which would have broken the one-time created-banner token display; fixed on the branch (commit 00aaafe) with tests before merge. Closing, branch deleted.
fen added spent time 40 seconds 2026-09-10 13:41:35 +00:00
fen added spent time 1 hour 23 minutes 2026-09-10 13:54:10 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Total Time Spent: 1 hour 25 minutes
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: poslop/palette#143