pgadmin4/web/pgadmin/browser/server_groups/servers/databases
Ashesh Vashi 9a76ed80bb
fix: enforce data isolation and harden shared servers in server mode (#9830)
pgAdmin 4 in server mode had no data isolation between users — any
authenticated user could access other users' private servers,
background processes, and debugger state by guessing object IDs.
The shared server feature had 21 vulnerabilities including credential
leaks, privilege escalation via passexec_cmd, and owner data
corruption via SQLAlchemy session mutations.

Centralized access control:
- New server_access.py with get_server(), get_server_group(),
  get_user_server_query() replacing ~20 unfiltered queries
- connection_manager() raises ObjectGone (HTTP 410) in server mode
  when access is denied — fixes 155+ unguarded callers
- UserScopedMixin.for_user() on 10 models replaces scattered
  user_id filters

Shared server isolation (all 21 audit issues):
- Expunge server from session before property merge to prevent
  owner data corruption
- Suppress passexec_cmd, post_connection_sql for non-owners in
  merge, API response, and ServerManager
- Override all 6 SSL/passfile connection_params keys from
  SharedServer; strip owner-only keys; sanitize on creation
- _is_non_owner() helper centralises 15+ inline ownership checks
- SharedServer lookup uses (osid, user_id) not name
- Unique constraint on SharedServer(osid, user_id)
- Tunnel/DB password save, change_password, clear_saved_password,
  clear_sshtunnel_password all branch on ownership
- Only owner can unshare (delete_shared_server guard)
- Session restore includes shared servers
- tunnel_port/tunnel_keep_alive copied from owner, not hardcoded

Tool/module hardening:
- All tool endpoints use get_server()
- Debugger function arguments scoped by user_id
- Background processes use Process.for_user()
- Workspace adhoc servers scoped to current user

Migration (schema version 49 -> 50):
- Add user_id to debugger_function_arguments composite PK
- Add indexes on server, sharedserver, servergroup
- Add unique constraint on sharedserver(osid, user_id)
2026-04-09 18:32:59 +05:30
..
casts Copyright updated for 2026 2026-01-05 13:33:45 +05:30
dbms_job_scheduler Copyright updated for 2026 2026-01-05 13:33:45 +05:30
event_triggers Copyright updated for 2026 2026-01-05 13:33:45 +05:30
extensions Copyright updated for 2026 2026-01-05 13:33:45 +05:30
foreign_data_wrappers Copyright updated for 2026 2026-01-05 13:33:45 +05:30
languages Copyright updated for 2026 2026-01-05 13:33:45 +05:30
publications Copyright updated for 2026 2026-01-05 13:33:45 +05:30
schemas fix: enforce data isolation and harden shared servers in server mode (#9830) 2026-04-09 18:32:59 +05:30
static Copyright updated for 2026 2026-01-05 13:33:45 +05:30
subscriptions Copyright updated for 2026 2026-01-05 13:33:45 +05:30
templates/databases 1) Fixed an issue where Default Privileges and Privileges not working correctly. #8369 2025-01-22 19:40:13 +05:30
tests Copyright updated for 2026 2026-01-05 13:33:45 +05:30
__init__.py fix: enforce data isolation and harden shared servers in server mode (#9830) 2026-04-09 18:32:59 +05:30
utils.py Copyright updated for 2026 2026-01-05 13:33:45 +05:30