Skip to content

Task: Close the write gap on the user API so members can't edit each other's records #2590

Description

@julhoang

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.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions