Remote Code Execution vulnerability when restoring PLAIN-format SQL dumps in server mode (pgAdmin 4)
Description
pgAdmin versions up to 9.10 are affected by a Remote Code Execution (RCE) vulnerability that occurs when running in server mode and performing restores from PLAIN-format dump files. This issue allows attackers to inject and execute arbitrary commands on the server hosting pgAdmin, posing a critical risk to the integrity and security of the database management system and underlying data.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
pgadmin4PyPI | < 9.11 | 9.11 |
Affected products
1- Range: 0
Patches
2d5a909f14cb9Plain SQL restore runs with '\restrict' option to prevent harmful psql meta-commands. #9368
2 files changed · +7 −36
docs/en_US/restore_dialog.rst+4 −0 modified@@ -29,6 +29,10 @@ restore process: copy of the backed-up object. * Select *Plain* to restore a plain SQL backup. When selecting this option all the other options will not be applicable. + **Note:** The plain SQL restore process is executed in the backend using + the psql command with the \restrict option. The purpose of \restrict is to + enhance security by preventing dangerous commands embedded in a plain text + dump file from being executed on a PostgreSQL server. * Select *Directory* to restore from a compressed directory-format archive. * Enter the complete path to the backup file in the *Filename* field.
web/pgadmin/tools/restore/__init__.py+3 −36 modified@@ -11,6 +11,7 @@ import json import re +import secrets from flask import render_template, request, current_app, Response from flask_babel import gettext as _ @@ -350,6 +351,7 @@ def get_sql_util_args(data, manager, server, filepath): :param filepath: File. :return: args list. """ + restrict_key = secrets.token_hex(32) args = [ '--host', manager.local_bind_host if manager.use_ssh_tunnel else server.host, @@ -358,6 +360,7 @@ def get_sql_util_args(data, manager, server, filepath): else str(server.port), '--username', server.username, '--dbname', data['database'], + '-c', f'\\restrict {restrict_key}', '--file', fs_short_path(filepath) ] @@ -375,43 +378,7 @@ def use_restore_utility(data, manager, server, driver, conn, filepath): return None, utility, args -def has_meta_commands(path, chunk_size=8 * 1024 * 1024): - """ - Quickly detect lines starting with '\' in large SQL files. - Works even when lines cross chunk boundaries. - """ - # Look for start-of-line pattern: beginning or after newline, - # optional spaces, then backslash - pattern = re.compile(br'(^|\n)[ \t]*\\') - - try: - with open(path, "rb") as f: - prev_tail = b"" - while chunk := f.read(chunk_size): - data = prev_tail + chunk - - # Search for pattern - if pattern.search(data): - return True - - # Keep a small tail to preserve line boundary context - prev_tail = data[-10:] # keep last few bytes - except FileNotFoundError: - current_app.logger.error("File not found.") - except PermissionError: - current_app.logger.error("Insufficient permissions to access.") - - return False - - def use_sql_utility(data, manager, server, filepath): - # Check the meta commands in file. - if has_meta_commands(filepath): - return _("Restore blocked: the selected PLAIN SQL file contains psql " - "meta-commands (for example \\! or \\i). For safety, " - "pgAdmin does not execute meta-commands from PLAIN restores. " - "Please remove meta-commands."), None, None - utility = manager.utility('sql') ret_val = does_utility_exist(utility) if ret_val:
1d397395f753Fixed remote code execution vulnerability when restoring PLAIN-format SQL dumps in server mode (CVE-2025-12762). #9320
2 files changed · +34 −1
docs/en_US/release_notes_9_10.rst+2 −1 modified@@ -40,4 +40,5 @@ Bug fixes | `Issue #9233 <https://github.com/pgadmin-org/pgadmin4/issues/9233>`_ - Fixed an issue where the Select All option on the columns tab of import/export data was not working in languages other than English. | `Issue #9240 <https://github.com/pgadmin-org/pgadmin4/issues/9240>`_ - Fixed an issue where the Debian build process failed with a "Sphinx module not found" error when using a Python virtual environment. | `Issue #9281 <https://github.com/pgadmin-org/pgadmin4/issues/9281>`_ - Fixed an issue where the last used storage directory was reset to blank, leading to access denied errors during backup or restore operations. - | `Issue #9304 <https://github.com/pgadmin-org/pgadmin4/issues/9304>`_ - Fixed an issue that prevented assigning multiple users to an RLS policy. \ No newline at end of file + | `Issue #9304 <https://github.com/pgadmin-org/pgadmin4/issues/9304>`_ - Fixed an issue that prevented assigning multiple users to an RLS policy. + | `Issue #9320 <https://github.com/pgadmin-org/pgadmin4/issues/9320>`_ - Fixed remote code execution vulnerability when restoring PLAIN-format SQL dumps in server mode (CVE-2025-12762). \ No newline at end of file
web/pgadmin/tools/restore/__init__.py+32 −0 modified@@ -10,6 +10,7 @@ """Implements Restore Utility""" import json +import re from flask import render_template, request, current_app, Response from flask_babel import gettext as _ @@ -374,7 +375,38 @@ def use_restore_utility(data, manager, server, driver, conn, filepath): return None, utility, args +def has_meta_commands(path, chunk_size=8 * 1024 * 1024): + """ + Quickly detect lines starting with '\' in large SQL files. + Works even when lines cross chunk boundaries. + """ + # Look for start-of-line pattern: beginning or after newline, + # optional spaces, then backslash + pattern = re.compile(br'(^|\n)[ \t]*\\') + + with open(path, "rb") as f: + prev_tail = b"" + while chunk := f.read(chunk_size): + data = prev_tail + chunk + + # Search for pattern + if pattern.search(data): + return True + + # Keep a small tail to preserve line boundary context + prev_tail = data[-10:] # keep last few bytes + + return False + + def use_sql_utility(data, manager, server, filepath): + # Check the meta commands in file. + if has_meta_commands(filepath): + return _("Restore blocked: the selected PLAIN SQL file contains psql " + "meta-commands (for example \\! or \\i). For safety, " + "pgAdmin does not execute meta-commands from PLAIN restores. " + "Please remove meta-commands."), None, None + utility = manager.utility('sql') ret_val = does_utility_exist(utility) if ret_val:
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-fxmw-jcgr-w44vghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-13780ghsaADVISORY
- github.com/pgadmin-org/pgadmin4/commit/1d397395f75320ca1d4ed5e9ca721c603415e836ghsaWEB
- github.com/pgadmin-org/pgadmin4/commit/d5a909f14cb9713d89b49481ad1929fad89f4576ghsaWEB
- github.com/pgadmin-org/pgadmin4/issues/9368ghsaissue-trackingWEB
- github.com/pgadmin-org/pgadmin4/pull/9426ghsaWEB
News mentions
0No linked articles in our index yet.