DEV Community

Auth By Example
Auth By Example

Posted on

A profile update endpoint can let users change fields they were never allowed to edit

Most apps have a PATCH /users/:id or PUT /projects/:id handler that checks one thing: can this caller edit this record? If yes, it takes the JSON body and passes it straight to the ORM's update call. The form in the UI only shows name, avatar and timezone, so nobody thinks about the other columns.

The other columns are still on the model. A user opens dev tools, copies the request their profile form sends, and adds "role": "admin" or "org_id": 42 to the body. The ownership check passes because it is their own profile, and the update writes every key it received. The same thing happens on records with an owner_id, status or approved_by column: a contributor who can edit the description of a ticket can also mark it approved or hand it to someone else.

Decide per field who can write it, and check that on the server for every key in the request. Users can change their own name, but only an org admin can change role, and nobody changes org_id through this endpoint at all. An explicit allowlist of writable fields per role works better than a blocklist, because a column added next month is denied until someone grants it. Reject the request with a 403 when it contains a field the caller can't set, instead of silently dropping it, so client bugs show up in testing.

To test it, log in as a regular user, send your normal profile update with "role": "admin" added, then fetch the user again. If the role changed, or the request returned 200 and the field was quietly ignored, look at the handler.

If you want these per-field rules in one policy instead of scattered across handlers, Permit.io is one way to do that (full disclosure, I work with Permit.io).

Top comments (0)