← Advisories

Pachno 1.0.6 (runSwitchUser()) Remote Vertical Privilege Escalation

High
Advisory ID
ZSL-2026-5985
Release Date
12 April 2026
Vendor
Daniel André Eikeland - https://github.com/pachno/pachno
Affected Version
1.0.6
CVE
N/A
Tested On
GNU/Linux, Apache2, PHP/7.4, MySQL/5.7 (MariaDB)
Summary

Pachno is an open-source collaboration platform (formerly known as The Bug Genie) designed for team project management, issue tracking, and documentation. It offers a module-based, customizable environment for software development and team workflows, distributed under the Mozilla Public License.

Description

The authorization check in the runSwitchUser() action evaluates the expression !canSaveConfiguration() && !hasCookie('original_username') and only forbids the request when both subexpressions are true. The presence of the original_username cookie is sufficient to satisfy the second condition, and that cookie is fully client-controlled. An authenticated low-privilege user who sets original_username to any value and then issues a request to switch to user ID 1 receives a fresh session token (token authentication) or password hash cookie (password authentication) belonging to the target user. This can be exploited to elevate privileges to administrator and impersonate arbitrary user accounts.

/core/modules/auth/controllers/Authentication.php: -------------------------------------------------- /** * Switch user action * * @Route(name="switch_to_user", url="/userswitch/switch/:user_id/:csrf_token") * @CsrfProtected * * @param framework\Request $request */ public function runSwitchUser(framework\Request $request) { if (!$this->getUser()->canSaveConfiguration() && !$request->hasCookie('original_username')) return $this->forward403(); $response = $this->getResponse(); $authentication_backend = framework\Settings::getAuthenticationBackend(); if ($request['user_id']) { $user = new entities\User($request['user_id']); if ($authentication_backend->getAuthenticationMethod() == framework\AuthenticationBackend::AUTHENTICATION_TYPE_TOKEN) { $response->setCookie('original_username', $request->getCookie('username')); $response->setCookie('original_session_token', $request->getCookie('session_token')); framework\Context::getResponse()->setCookie('username', $user->getUsername()); framework\Context::getResponse()->setCookie('session_token', $user->createUserSession()->getToken()); } else { $response->setCookie('original_username', $request->getCookie('username')); $response->setCookie('original_password', $request->getCookie('password')); framework\Context::getResponse()->setCookie('password', $user->getHashPassword()); framework\Context::getResponse()->setCookie('username', $user->getUsername()); } } else { if ($authentication_backend->getAuthenticationMethod() == framework\AuthenticationBackend::AUTHENTICATION_TYPE_TOKEN) { $response->setCookie('username', $request->getCookie('original_username')); $response->setCookie('session_token', $request->getCookie('original_session_token')); framework\Context::getResponse()->deleteCookie('original_session_token'); framework\Context::getResponse()->deleteCookie('original_username'); } else { $response->setCookie('username', $request->getCookie('original_username')); $response->setCookie('password', $request->getCookie('original_password')); framework\Context::getResponse()->deleteCookie('original_password'); framework\Context::getResponse()->deleteCookie('original_username'); } } $this->forward($this->getRouting()->generate('home')); }
Proof of Concept
Disclosure Timeline
06.04.2026Vulnerability discovered.
09.04.2026Vendor contacted.
11.04.2026No response from the vendor.
12.04.2026Public security advisory released.
Credits
Vulnerability discovered by Gjoko Krstic
References
N/A
Changelog
12.04.2026Initial release