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](https://www.pgadmin.org/docs/pgadmin4/9.18/release_notes_9_18.html).
pgAdmin is the leading open-source graphical management tool for PostgreSQL. For more information, please see [the website](https://www.pgadmin.org/). 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](https://www.pgadmin.org/download/).
