Skip to content

fix(api): GET /api/purchases/approve/{id} approves a purchase (a side-effecting GET) #549

Closed

Description

@cristim

Summary

The public email-token approve route is registered for GET as well as POST, and the handler performs the approval on either method. Anything that issues a GET to the emailed link approves the purchase: mail security link scanners, URL previewers, browser prefetch.

Location (origin/main 5659f3b)

  • internal/api/router.go:163 registers GET /api/purchases/approve/ with approvePurchaseHandler, AuthPublic; :164 registers the POST.
  • internal/api/router.go:588 approvePurchaseHandler and internal/api/handler_purchases.go:594 approvePurchase do not branch on the HTTP method.
  • internal/api/router.go:568 resolveApprovalToken accepts the token from the query string on GET.
  • Precedent in the same router: the revoke email link (revokeViaEmailTokenHandler) renders a confirmation form on GET and executes only on POST.

Failure scenario

An approver's mail gateway pre-fetches GET /api/purchases/approve/{id}?token=... to scan the link. The purchase is approved and executed without any human click. The scan has no session and needs nothing beyond the token already in the URL.

Suggested fix

GET renders a confirmation page (or redirects to the SPA approval modal); only POST with the token in the body approves, matching the revoke flow. The one-click email link still works: one click opens the confirmation, one more confirms.

Context

Found while implementing #529 (PR #548). Related: #529 (token-authorized details read needs a GET path too, see below), #71 and #77 (token hashing at rest). Searched for an existing issue on side-effecting GET approval; none found.

Acceptance

GET /api/purchases/approve/{id}?token=... never changes purchase state, and approving from the email link still works through a POST.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions