Problem
The permission rule protecting the user API (/api/v1/users/) was written as a list of specific write operations to block. PATCH — the operation for updating a few fields on an existing record — was left off that list, so it fell through to the rule for ordinary reading: any signed-in member passes the check on any other member's record.
Nothing is actually being modified today, because a second safeguard sits behind the permission check: ordinary members are handed a stripped-down view of a user exposing only an id and display name, both marked unchangeable. So the request is accepted, reports success, and writes nothing. That safeguard is the only thing standing between this and a real cross-member edit — and loosening it is a plausible change to make (letting people rename themselves through the main endpoint, say). Whoever made it would have no signal they had also opened up editing of everyone else's records.
What we want
- Protect every write operation with the same staff check, expressed as a single rule rather than a list of operations to remember, so nothing can be left off it and anything added later is protected by default.
- Add test coverage for this endpoint, which currently has none — including pinning who sees which user fields, since that second safeguard is doing real security work.
Acceptance criteria
- A signed-in member attempting to create, edit, or delete another member's record is refused, for every write operation.
- Reading is unchanged: available to signed-in users, refused for anonymous visitors.
- Staff and admin writes still work, with a test proving it, so tightening the rule doesn't take admin capability with it.
- Tests pin which fields an ordinary member sees on another user versus a staff member.
Out of scope
The profile editing endpoint members actually use, and what the API exposes to staff. This is about who may write, not about reshaping the data.
Notes / risk
Nothing outside the site's own profile page calls this endpoint, and that page doesn't use the affected path, so there is no user-facing behaviour to regress. The one visible change is that an unauthorised edit now returns a clear refusal instead of a misleading success.
Problem
The permission rule protecting the user API (
/api/v1/users/) was written as a list of specific write operations to block.PATCH— the operation for updating a few fields on an existing record — was left off that list, so it fell through to the rule for ordinary reading: any signed-in member passes the check on any other member's record.Nothing is actually being modified today, because a second safeguard sits behind the permission check: ordinary members are handed a stripped-down view of a user exposing only an id and display name, both marked unchangeable. So the request is accepted, reports success, and writes nothing. That safeguard is the only thing standing between this and a real cross-member edit — and loosening it is a plausible change to make (letting people rename themselves through the main endpoint, say). Whoever made it would have no signal they had also opened up editing of everyone else's records.
What we want
Acceptance criteria
Out of scope
The profile editing endpoint members actually use, and what the API exposes to staff. This is about who may write, not about reshaping the data.
Notes / risk
Nothing outside the site's own profile page calls this endpoint, and that page doesn't use the affected path, so there is no user-facing behaviour to regress. The one visible change is that an unauthorised edit now returns a clear refusal instead of a misleading success.