pgAdmin 4 v9.18 Released

Posted on 2026-09-17 by pgAdmin Development Team
Related Open Source

The pgAdmin Development Team is pleased to announce the release of pgAdmin 4 version 9.18. This release of pgAdmin 4 includes 29 bug fixes and new features, including fixes for four security vulnerabilities (CVE-2026-86861 through CVE-2026-86864). For more details, please see the release notes.

pgAdmin is the leading open-source graphical management tool for PostgreSQL. For more information, please see the website.

Notable changes in this release include:

Features

  • Collapse and restore the Object Explorer by re-clicking the current workspace icon, in the manner of the VS Code side bar, remembering the choice across refreshes. A keyboard shortcut, Ctrl+Alt+B by default, does the same thing and can be changed through the new toggle_object_explorer preference.
  • Harden the default Content-Security-Policy so inline scripts run under a per-request nonce rather than a blanket 'unsafe-inline', and drop 'unsafe-eval'. style-src keeps 'unsafe-inline', because MUI and React inject runtime styles and inline style attributes that cannot carry a nonce, and development bundles have 'unsafe-eval' re-added automatically when DEBUG is set.

Security Fixes

  • Fix an authentication bypass in Webserver authentication mode, where get_user() fell back to reading the configured WEBSERVER_REMOTE_USER name from the inbound request headers when it was absent from the WSGI environment. Because a header is written by whoever sends the request, any client that could reach pgAdmin could assert any identity, including an administrator's, without presenting a credential. A header-asserted identity is now opt-in, restricted to a configured list of trusted proxies with an optional shared secret, and refused for accounts whose authentication source is not webserver (CVE-2026-86863).
  • Fix argument and connection-string injection in the Backup tool, where the client-supplied database name was appended to the pg_dump argument vector as a bare positional value. Because getopt_long permutes arguments, a value beginning with a dash supplied further options such as --file, overriding the storage-confined output path; and because libpq expands a database name containing an equals sign into a full connection string, the same field could redirect the connection, and the password exported in PGPASSWORD, to a host of the caller's choosing. The database name is now passed through the PGDATABASE environment variable, which libpq never expands (CVE-2026-86864).
  • Fix connection-string injection in the Restore and Maintenance tools, where the client-supplied database name was passed straight to --dbname and could likewise redirect the connection, and the exported password, to a server of the caller's choosing (CVE-2026-86862).
  • Fix a time-of-check to time-of-use flaw in the File Manager's save_file endpoint, which backs saving from the Query Tool and ERD: the requested path was validated with check_access_permission() and then opened with a plain open(), so a symbolic link planted in between was followed, writing outside the user's storage directory. This is the write sink that CVE-2026-7819's hardening of the separate upload path did not cover (CVE-2026-86861).
  • Refuse HTTP redirects on LLM API requests, rather than following a Location header on to a destination the ALLOWED_LLM_API_URLS check was never applied to. This is hardening rather than a fix for an exploitable flaw, since returning the redirect at all requires control of a host already on the allowlist.
  • Reject an empty or null Username when importing a non-shared server, which previously imported cleanly and left a server that libpq would silently authenticate as the OS account running pgAdmin rather than reject outright.

Bugs/Housekeeping

  • Fix login being impossible against Flask-Security-Too 5.8.2, which corrected a long-standing inversion in UserMixin.is_locked() that pgAdmin's own is_locked() had been written against.
  • Fix inherited columns in the Table dialog being editable and deletable, and the Data type dropdown on the expanded Definition tab offering every type rather than honouring the allowed-type restriction applied inline.
  • Reinstate dependency ordering of the script Schema Diff generates, which had been lost since the React port left dependLevel unset.
  • Fix Schema Diff reporting false differences for SERIAL and BIGSERIAL columns, duplicating any column that also differs when recreating a foreign table, losing a foreign table column's collation, injecting whitespace into an applied function or procedure body, generating SQL that PostgreSQL rejects when a sequence's MINVALUE is raised above its current value, and reporting a comparison that fails part way through as a success.
  • Share concurrent identical GET requests behind getNodeAjaxOptions() so a wide table's Columns tab no longer fires one duplicate get_types request per column row.
  • Fix the argument grid on the Definition tab of a user-defined function or procedure refusing to delete, or add, a row in edit mode.
  • Omit the redundant TABLESPACE pg_default clause from generated index SQL, which was invalid on a partitioned table.
  • Fix a crash when a per-server Password Exec Command is used with a service-only (pg_service.conf) connection, which leaves host, port and username unset.
  • Accept SharedUsername when importing a shared server from a servers.json definition, instead of insisting on Username for every server.
  • Render the Validate binary path dialog as HTML, instead of showing the raw markup.
  • Remove a trailing quote from the Windows installer's ProductVersion, and fix the existingSecret path in the Helm deployment template.
  • Skip importing and initialising the Kerberos, LDAP, MFA, OAuth2 and Webserver authentication providers unless SERVER_MODE is set, leaving desktop mode with internal authentication alone.
  • Bump JavaScript and Python third-party dependencies, and update the message catalogs, including a fix for the Korean catalog that had not been recompiled since November 2025.

Builds for Windows and macOS are available now, along with a Python Wheel, Docker Container, RPM, DEB Package, and source code tarball from the download area.