Skip to content

Commit 8c05e11

Browse files
committed
fix(api): implement safe update logic for user data endpoint
- Prevent privilege escalation by not saving the entire request body - Perform a partial update of user data, allowing only safe fields to be modified - Protect critical fields: appRole, dashboardRole, id, createdAt, email - Allow update of feedActionStatus as it's considered safe user interaction data - Future-proof the logic for potential safe fields addition
1 parent f670c02 commit 8c05e11

File tree

1 file changed

+37
-1
lines changed

1 file changed

+37
-1
lines changed

routes/api/v1/data/[id]/index.dart

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,45 @@ Future<Response> _handlePut(
324324
case 'user':
325325
{
326326
final repo = context.read<DataRepository<User>>();
327+
328+
// --- Safe User Update Logic ---
329+
// To prevent security vulnerabilities like privilege escalation, we do not
330+
// simply save the entire request body. Instead, we perform a safe,
331+
// partial update.
332+
333+
// 1. Fetch the existing, trusted user object from the database.
334+
// This ensures we have the current, authoritative state of the user,
335+
// including their correct roles and ID.
336+
final existingUser = await repo.read(
337+
id: id,
338+
userId: userIdForRepoCall,
339+
);
340+
341+
// 2. Create a new User object by merging only the allowed, safe-to-update
342+
// fields from the incoming request (`itemToUpdate`) into the
343+
// existing user data.
344+
// This is the most critical step. It guarantees that a user cannot
345+
// change their own `appRole`, `dashboardRole`, `id`, or `createdAt`
346+
// fields, even if they include them in the request payload.
347+
// The `email` field is also protected here, as changing it requires a
348+
// separate, secure verification flow (e.g., via a dedicated endpoint)
349+
// and should not be done through this generic data endpoint.
350+
final updatedUser = existingUser.copyWith(
351+
// `feedActionStatus` is considered safe for a user to update as it
352+
// only tracks their interaction with UI elements.
353+
feedActionStatus: (itemToUpdate as User).feedActionStatus,
354+
355+
// FUTURE: If a `displayName` field were added to the User model,
356+
// it would also be considered safe and could be updated here:
357+
// displayName: itemToUpdate.displayName,
358+
);
359+
360+
// 3. Save the securely merged user object back to the database.
361+
// The repository will now update the user record with our safely
362+
// constructed `updatedUser` object.
327363
updatedItem = await repo.update(
328364
id: id,
329-
item: itemToUpdate as User,
365+
item: updatedUser,
330366
userId: userIdForRepoCall,
331367
);
332368
}

0 commit comments

Comments
 (0)