# pyLoad: Privilege revocation and password change through the REST API do not invalidate the user's session

pyLoad's REST API set_user_permission and change_password update the DB but never invalidate the Flask session, so demoted or rotated users keep admin rights for up to a month.

- Payout: Research
- Severity: high
- Program: pyLoad
- Found by: arpitjain099
- Disclosed: 2026-10-09
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-jq7h-wrvp-3rgx
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-jq7h-wrvp-3rgx
- Tags: area:web domain:web impact:integrity impact:privesc kind:research platform:ghsa sev:high tech:python technique:incomplete-fix technique:source-review vuln:access-control vuln:auth-bypass vuln:privilege-escalation

**Target:** Flask web session / REST API (/api/<func>)
**Root cause:** Role and perms are copied into the Flask session at login and read back from the session by login_required and apikey_auth's session branch; Api.set_user_permission and Api.change_password only write the database and never delete session files, unlike the json_blueprint handlers patched for GHSA-66hx-chf7-3332.
**Steps:**
1. Log in as a user to obtain a session cookie.
2. As admin, POST `/api/set_user_permission` demoting the user from role 0 to role 1 with permission 0; DB updates immediately.
3. Reuse the demoted user's existing session: `/api/get_userdir` returns 200, `/settings` loads, and `/api/set_config_value` still writes `reconnect.script` (admin-only, CVE-2026-33509).
4. Control: same change via `/json/update_users` makes the same request return 401 and `/settings` redirect to login.
5. Password path: POST `/api/change_password`; old password refused at login, new accepted, but the session opened under the old password still works; via `/json/change_password` it is dropped.
**How found:** Noticed the GHSA-66hx-chf7-3332 fix only deleted session files in json_blueprint.py's three WebUI form handlers; traced set_session in webui/app/helpers.py and saw login_required/apikey_auth read role/perms from the session, then checked core/api/__init__.py where set_user_permission and change_password write DB and return, and confirmed both are exported over /api and listed in the served OpenAPI spec.
**Exploitation:** An admin revoking privileges or rotating a password through the documented /api endpoints believes the user is evicted; the user's existing session cookie remains valid and retains admin-only capabilities such as writing reconnect.script via /api/set_config_value, for up to webui.session_lifetime (default 44640 minutes, ~1 month).
**Escalation:** Stale session retains admin-only config write (reconnect.script), the sink behind CVE-2026-33509, enabling command execution on reconnect.
**Insight:** When a fix for session invalidation lands in one blueprint, enumerate every other route that mutates the same DB fields (here the /api/<func> exports and the OpenAPI spec) and test each with a paired control; also check whether auth reads identity from session vs DB per request, since the API-key branch was immune while the session branch was not.

