You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
sec(api): planned-purchase DELETE checks update-any on the key owner, not the API key's effective permissions #979
Found while independently reviewing #978, which closes #678 and is stacked on #975.
Problem
authorizePlannedPurchaseCancel (internal/api/handler_purchases.go, the DELETE /api/purchases/planned/{id} route) grants full scope to update-any with h.auth.HasPermissionAPI(ctx, session.UserID, ...). That checks the owning user's permissions, not the API key's effective permissions.
So a user-API-key session whose key holds only a narrow verb (for example cancel-own or delete on purchases) can cancel any user's planned purchase whenever the key's owner holds update-any. The key's own scope is ignored for that branch.
This is an API-key scope escalation, separate from the missing-Constraints class that #961 tracks:
On main, both update-any and cancel-any are checked against the owner (handler_purchases.go:439-447 at the time of writing).
Every verb that authorizes this route should be evaluated against the session's effective permissions, the same way #957 and the revoke and cancel paths do. For a user-API-key session that means the key's permissions, intersected with the owner's. The checks should also apply that grant's Constraints (#961).
Suggested test
A user-API-key session whose key has only cancel-own on purchases, and whose owner holds update-any, must get 403 or 404 deleting another user's planned purchase.
Activity
IAmJSD commentedon Oct 16, 2026
Claiming: working on this
fix(api): evaluate planned-purchase full-scope verbs on the API key, …
fix(api): bound update-any by its Constraints on planned-purchase DEL…