CVSS 8.3 · Mass assignment (CWE-915) · Fixed in Dolibarr 24.0.0
The front desk refuses to change the CEO's password. But the membership clerk's window, which nobody thought to lock will happily do it, if you slide the very same form through it.
The attack in six steps
- The front door says no: Ask the account interface to change the admin's password and it refuses. (403 Forbidden)
- Send the identical change to the membership desk: A completely different window into the same data. (this is the break)
- It checks only one thing: can you add members?: A routine permission that has nothing to do with login accounts.
- It accepts every field you sent: Including two that quietly belong to the linked account: the target and the new password.
- Point them at the administrator: The admin's stored password is overwritten with one you chose. (200 OK)
- Log in as admin with your password: Same instance, same key, opposite answer. → full takeover.
Every serious application guards one rule more carefully than any other: who is allowed to change a password. Get that wrong and everything else, every permission, every record, sits downstream of a single mistake. Dolibarr guards it well. Ask its user-management screen to change the administrator's password without the right to do so, and it says no, flatly.
This is the story of how the same request, same instance, same key, same target, gets a yes simply by being posted through a different window.
Dolibarr is the back office for a lot of small clubs, associations and companies. Alongside its login accounts, it has a separate feature for managing members: the people who belong to a club or association. Different feature, different screen, different permission. The person at the membership desk is trusted to add and edit members all day, and that was meant to be the whole of what they could do.
The bug is that the membership desk quietly has a spare key to the login accounts, and nobody noticed it was on the ring.
Two doors into the same room
The rule we applied over and over in this security research is simple: when one part of an app guards something, go and find every other part that can touch the same thing, and check the guard is there too. Applications grow in layers, and the second door into a room is the one that gets forgotten.
Dolibarr's account-management screen treats a password with the respect it deserves. Before it will change one, it checks that the caller actually holds the specific right to manage credentials. A membership key does not, so through that door the answer is a clean refusal.
The members screen is a different door into a database that, it turns out, overlaps. A member record can be linked to a login account. And when you create or edit a member, the members screen does something careless: it takes every field you sent it and writes it onto the record, no questions asked. It checks one thing at the entrance, “are you allowed to manage members?”, and then trusts everything that follows.
From an application security perspective, this is the dangerous shape of a mass-assignment vulnerability: a legitimate write endpoint accepts fields that belong to a more privileged part of the application's data model.
The two fields that don't belong
Buried in that pile of accepted fields are two that were never really member fields at all: one that says which login account this member is attached to, and one that says what that account's password should be.
So the attacker fills in a member form, points the “attached account” field at the administrator, sets the “password” field to a string of their choosing, and posts it to the membership desk. The desk checks that the caller can manage members, they can, and then dutifully writes the new password onto the linked account. The linked account is the administrator.
The same password change the front door refused a moment ago is now done, through a window that only ever asked whether you could file paperwork for a club.
What it costs
The instant that write lands, the real administrator is locked out. Their old password simply stops working. The attacker logs straight in with the password they picked. No cracking, no stolen session, no clever timing. One ordinary request from an account that holds nothing but membership permissions, and the whole system changes hands.
There is one soft edge worth being precise about. If a second administrator already exists, recovery is easy. If not, getting back in means an out-of-band reset from the database or the command line, which is why the availability impact is scored as a disruption rather than total destruction. Confidentiality and integrity, though, are at the top of the scale, because by this point the attacker owns everything.
And the permission that makes it all possible is one an administrator hands out without a second thought. “You can manage our members” sounds harmless. It is exactly the access you would give a volunteer registrar at a club. Dolibarr even lists Members and Users as separate, unrelated modules, so nobody granting the one imagines they are also granting the other. A leaked membership key, a compromised registrar, an over-trusted volunteer, any of them is now a path to full control.
What closes it
Dolibarr already had the correct behaviour written down in the account-management screen, which refuses credential fields outright and demands the password right before it will touch one. The fix in 24.0.0 brings the members screen under the same discipline: sensitive fields are rejected before they are ever written, the password right is required, and the quiet sync onto the linked account no longer fires by default.
The lesson outlives this one screen. An interface should never assume that every field a caller can send is a field they should be allowed to set. The durable fix is a short, explicit list of the fields each screen accepts, not a scramble to block each dangerous one after it is found. When one part of the code already gets a sensitive check right, the next part that touches the same data is not a fresh design problem. It is a copy you owe yourself.
That is also why API security testing needs to look beyond whether an endpoint has an authorization check. A permission can exist and still be applied to the wrong data, the wrong field, or the wrong route. Testing those alternate paths is what turns a code-level suspicion into a validated security vulnerability.
The fix. Upgrade to Dolibarr 24.0.0. That closes this finding. Want to know where your own app disagrees with itself? → Start with a free CodeAnt pentest
















