@@ -324,9 +324,45 @@ Future<Response> _handlePut(
324
324
case 'user' :
325
325
{
326
326
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.
327
363
updatedItem = await repo.update (
328
364
id: id,
329
- item: itemToUpdate as User ,
365
+ item: updatedUser ,
330
366
userId: userIdForRepoCall,
331
367
);
332
368
}
0 commit comments