Any authenticated user (including BASIC role) can escalate to ADMIN on servers migrated from password authentication to OpenID Connect. Three weaknesses combine: POST /account/change-password has no authorization check, allowing any session to overwrite the password hash; the inactive password auth row is never removed on migration; and the login endpoint accepts a client-supplied loginMethod that bypasses the server's active auth configuration. Together these allow an attacker to set a known password and authenticate as the anonymous admin account created during the multiuser migration.
packages/sync-server/src/app-account.js:120-132 — the /account/change-password route validates only that a session exists. No admin role check is performed
app.post('/change-password', (req, res) => {
const session = validateSession(req, res); // only checks token validity
if (!session) return;
const { error } = changePassword(req.body.password); // no isAdmin() check
packages/sync-server/src/accounts/password.js:113-125 — changePassword() updates the hash with no current-password confirmation:
export function changePassword(newPassword) {
accountDb.mutate("UPDATE auth SET extra_data = ? WHERE method = 'password'", [hashed]);
}
packages/sync-server/src/accounts/password.js:56-62 — loginWithPassword() always authenticates as the user with user_name = '', which is created by the multiuser migration with role = 'ADMIN':
const sessionRow = accountDb.first(
'SELECT * FROM sessions WHERE auth_method = ?', ['password']
);
packages/sync-server/src/account-db.js:56-63 — a client can force the password login method regardless of server configuration by sending loginMethod in the request body:
if (req.body.loginMethod && config.get('allowedLoginMethods').includes(req.body.loginMethod)) {
return req.body.loginMethod;
}
When a server is migrated from...
26.4.0Exploitability
AV:NAC:LPR:LUI:NScope
S:UImpact
C:HI:HA:H8.8/CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H