Action not permitted
Modal body text goes here.
Modal Title
Modal Body
WID-SEC-W-2026-2613
Vulnerability from csaf_certbund - Published: 2026-08-02 22:00 - Updated: 2026-08-02 22:00Summary
pgAdmin: Mehrere Schwachstellen
Severity
Hoch
Notes
Das BSI ist als Anbieter für die eigenen, zur Nutzung bereitgestellten Inhalte nach den allgemeinen Gesetzen verantwortlich. Nutzerinnen und Nutzer sind jedoch dafür verantwortlich, die Verwendung und/oder die Umsetzung der mit den Inhalten bereitgestellten Informationen sorgfältig im Einzelfall zu prüfen.
Produktbeschreibung: pgAdmin ist eine Verwaltungs- und Entwicklungsplattform für die PostgreSQL-Datenbank.
Angriff: Ein Angreifer kann mehrere Schwachstellen in pgAdmin ausnutzen, um beliebigen Programmcode auszuführen, SQL-Injection-Angriffe durchzuführen, Sicherheitsmaßnahmen zu umgehen, vertrauliche Informationen offenzulegen und Daten zu manipulieren.
Betroffene Betriebssysteme: - Sonstiges
- UNIX
- Windows
Affected products
Known affected
1 product
| Product | Identifier | Version | Remediation |
|---|---|---|---|
|
Open Source pgAdmin <9.17
Open Source / pgAdmin
|
<9.17 |
Affected products
Known affected
1 product, the same list as for
CVE-2026-17346
Affected products
Known affected
1 product, the same list as for
CVE-2026-17346
Affected products
Known affected
1 product, the same list as for
CVE-2026-17346
Affected products
Known affected
1 product, the same list as for
CVE-2026-17346
Affected products
Known affected
1 product, the same list as for
CVE-2026-17346
Affected products
Known affected
1 product, the same list as for
CVE-2026-17346
References
10 references
{
"document": {
"aggregate_severity": {
"text": "hoch"
},
"category": "csaf_base",
"csaf_version": "2.0",
"distribution": {
"tlp": {
"label": "WHITE",
"url": "https://www.first.org/tlp/"
}
},
"lang": "de-DE",
"notes": [
{
"category": "legal_disclaimer",
"text": "Das BSI ist als Anbieter f\u00fcr die eigenen, zur Nutzung bereitgestellten Inhalte nach den allgemeinen Gesetzen verantwortlich. Nutzerinnen und Nutzer sind jedoch daf\u00fcr verantwortlich, die Verwendung und/oder die Umsetzung der mit den Inhalten bereitgestellten Informationen sorgf\u00e4ltig im Einzelfall zu pr\u00fcfen."
},
{
"category": "description",
"text": "pgAdmin ist eine Verwaltungs- und Entwicklungsplattform f\u00fcr die PostgreSQL-Datenbank.",
"title": "Produktbeschreibung"
},
{
"category": "summary",
"text": "Ein Angreifer kann mehrere Schwachstellen in pgAdmin ausnutzen, um beliebigen Programmcode auszuf\u00fchren, SQL-Injection-Angriffe durchzuf\u00fchren, Sicherheitsma\u00dfnahmen zu umgehen, vertrauliche Informationen offenzulegen und Daten zu manipulieren.",
"title": "Angriff"
},
{
"category": "general",
"text": "- Sonstiges\n- UNIX\n- Windows",
"title": "Betroffene Betriebssysteme"
}
],
"publisher": {
"category": "other",
"contact_details": "csaf-provider@cert-bund.de",
"name": "Bundesamt f\u00fcr Sicherheit in der Informationstechnik",
"namespace": "https://www.bsi.bund.de"
},
"references": [
{
"category": "self",
"summary": "WID-SEC-W-2026-2613 - CSAF Version",
"url": "https://wid.cert-bund.de/.well-known/csaf/white/2026/wid-sec-w-2026-2613.json"
},
{
"category": "self",
"summary": "WID-SEC-2026-2613 - Portal Version",
"url": "https://wid.cert-bund.de/portal/wid/securityadvisory?name=WID-SEC-2026-2613"
},
{
"category": "external",
"summary": "pgAdmin Release Notes vom 2026-08-02",
"url": "http://www.pgadmin.org/news/#124"
},
{
"category": "external",
"summary": "GitHub Advisory Database vom 2026-08-02",
"url": "https://github.com/advisories/GHSA-VMJ8-4452-JJ72"
},
{
"category": "external",
"summary": "GitHub Advisory Database vom 2026-08-02",
"url": "https://github.com/advisories/GHSA-F649-FJV9-QGCG"
},
{
"category": "external",
"summary": "GitHub Advisory Database vom 2026-08-02",
"url": "https://github.com/advisories/GHSA-RM8J-FQ8G-RCJC"
},
{
"category": "external",
"summary": "GitHub Advisory Database vom 2026-08-02",
"url": "https://github.com/advisories/GHSA-P547-RJMG-JQR4"
},
{
"category": "external",
"summary": "GitHub Advisory Database vom 2026-08-02",
"url": "https://github.com/advisories/GHSA-4PJ2-VQ9J-XJ3G"
},
{
"category": "external",
"summary": "GitHub Advisory Database vom 2026-08-02",
"url": "https://github.com/advisories/GHSA-V5GM-27GP-4F7W"
},
{
"category": "external",
"summary": "GitHub Advisory Database vom 2026-08-02",
"url": "https://github.com/advisories/GHSA-3H25-H4M7-GR36"
}
],
"source_lang": "en-US",
"title": "pgAdmin: Mehrere Schwachstellen",
"tracking": {
"current_release_date": "2026-08-02T22:00:00.000+00:00",
"generator": {
"date": "2026-08-03T11:21:10.253+00:00",
"engine": {
"name": "BSI-WID",
"version": "1.6.0"
}
},
"id": "WID-SEC-W-2026-2613",
"initial_release_date": "2026-08-02T22:00:00.000+00:00",
"revision_history": [
{
"date": "2026-08-02T22:00:00.000+00:00",
"number": "1",
"summary": "Initiale Fassung"
}
],
"status": "final",
"version": "1"
}
},
"product_tree": {
"branches": [
{
"branches": [
{
"branches": [
{
"category": "product_version_range",
"name": "\u003c9.17",
"product": {
"name": "Open Source pgAdmin \u003c9.17",
"product_id": "T057456"
}
},
{
"category": "product_version",
"name": "9.17",
"product": {
"name": "Open Source pgAdmin 9.17",
"product_id": "T057456-fixed",
"product_identification_helper": {
"cpe": "cpe:/a:pgadmin:pgadmin:9.17"
}
}
}
],
"category": "product_name",
"name": "pgAdmin"
}
],
"category": "vendor",
"name": "Open Source"
}
]
},
"vulnerabilities": [
{
"cve": "CVE-2026-17346",
"product_status": {
"known_affected": [
"T057456"
]
},
"release_date": "2026-08-02T22:00:00.000+00:00",
"title": "CVE-2026-17346"
},
{
"cve": "CVE-2026-17347",
"product_status": {
"known_affected": [
"T057456"
]
},
"release_date": "2026-08-02T22:00:00.000+00:00",
"title": "CVE-2026-17347"
},
{
"cve": "CVE-2026-17349",
"product_status": {
"known_affected": [
"T057456"
]
},
"release_date": "2026-08-02T22:00:00.000+00:00",
"title": "CVE-2026-17349"
},
{
"cve": "CVE-2026-17350",
"product_status": {
"known_affected": [
"T057456"
]
},
"release_date": "2026-08-02T22:00:00.000+00:00",
"title": "CVE-2026-17350"
},
{
"cve": "CVE-2026-17351",
"product_status": {
"known_affected": [
"T057456"
]
},
"release_date": "2026-08-02T22:00:00.000+00:00",
"title": "CVE-2026-17351"
},
{
"cve": "CVE-2026-17566",
"product_status": {
"known_affected": [
"T057456"
]
},
"release_date": "2026-08-02T22:00:00.000+00:00",
"title": "CVE-2026-17566"
},
{
"cve": "CVE-2026-17348",
"product_status": {
"known_affected": [
"T057456"
]
},
"release_date": "2026-08-02T22:00:00.000+00:00",
"title": "CVE-2026-17348"
}
]
}
CVE-2026-17346 (GCVE-0-2026-17346)
Vulnerability from cvelistv5 – Published: 2026-07-31 15:59 – Updated: 2026-08-01 03:56
VLAI
EPSS
VEX
Title
pgAdmin 4: SQL injection via unescaped object names in index Statistics and publication/subscription dependency views (incomplete fix for CVE-2026-12044)
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.
Severity
SSVC
Exploitation: none
Automatable: no
Technical Impact: total
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-07-31 00:00 UTC
CWE
- CWE-89 - Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
Assigner
References
3 references
| URL | Tags |
|---|---|
| https://github.com/pgadmin-org/pgadmin4/issues/10193 | issue-tracking |
| https://github.com/pgadmin-org/pgadmin4/commit/73… | patch |
| https://github.com/pgadmin-org/pgadmin4/commit/f7… | patch |
Impacted products
2 products
| Vendor | Product | Version | |
|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Affected:
1.0 , < 9.17
(custom)
|
|
| pgadmin.org | pgAdmin 4 |
Affected:
5.0 , < 9.17
(custom)
|
{
"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-17347 (GCVE-0-2026-17347)
Vulnerability from cvelistv5 – Published: 2026-07-31 15:59 – Updated: 2026-08-01 03:56
VLAI
EPSS
VEX
Title
pgAdmin 4: OS command injection in MASTER_PASSWORD_HOOK via untrusted username substitution
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.
Severity
SSVC
Exploitation: none
Automatable: no
Technical Impact: total
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-07-31 00:00 UTC
CWE
Assigner
References
3 references
| URL | Tags |
|---|---|
| https://github.com/pgadmin-org/pgadmin4/issues/10191 | issue-tracking |
| https://github.com/pgadmin-org/pgadmin4/commit/ea… | patch |
| https://github.com/pgadmin-org/pgadmin4/commit/e7… | patch |
Impacted products
1 product
| Vendor | Product | Version | |
|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Affected:
7.2 , < 9.17
(custom)
|
Credits
{
"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-17348 (GCVE-0-2026-17348)
Vulnerability from cvelistv5 – Published: 2026-07-31 15:59 – Updated: 2026-07-31 17:23
VLAI
EPSS
VEX
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)
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.
Severity
6.5 (Medium)
SSVC
Exploitation: none
Automatable: yes
Technical Impact: partial
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-07-31 17:22 UTC
CWE
- CWE-306 - Missing Authentication for Critical Function
Assigner
References
2 references
| URL | Tags |
|---|---|
| https://github.com/pgadmin-org/pgadmin4/issues/10194 | issue-tracking |
| https://github.com/pgadmin-org/pgadmin4/commit/24… | patch |
Impacted products
3 products
| Vendor | Product | Version | |
|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Affected:
1.0 , < 9.17
(custom)
|
|
| pgadmin.org | pgAdmin 4 |
Affected:
4.18 , < 9.17
(custom)
|
|
| pgadmin.org | pgAdmin 4 |
Affected:
8.2 , < 9.17
(custom)
|
Credits
{
"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-17349 (GCVE-0-2026-17349)
Vulnerability from cvelistv5 – Published: 2026-07-31 15:59 – Updated: 2026-08-01 03:56
VLAI
EPSS
VEX
Title
pgAdmin 4: Adhoc server clone leaks another user's stored database credentials and ownership to a non-owner
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.
Severity
9.6 (Critical)
SSVC
Exploitation: none
Automatable: no
Technical Impact: total
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-07-31 00:00 UTC
CWE
Assigner
References
3 references
| URL | Tags |
|---|---|
| https://github.com/pgadmin-org/pgadmin4/issues/10200 | issue-tracking |
| https://github.com/pgadmin-org/pgadmin4/commit/a7… | related |
| https://github.com/pgadmin-org/pgadmin4/commit/64… | patch |
Impacted products
1 product
| Vendor | Product | Version | |
|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Affected:
9.0 , < 9.17
(custom)
|
Credits
{
"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-17350 (GCVE-0-2026-17350)
Vulnerability from cvelistv5 – Published: 2026-07-31 16:00 – Updated: 2026-07-31 17:05
VLAI
EPSS
VEX
Title
pgAdmin 4: Tool permission bypass via backend routes and Socket.IO handlers
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.
Severity
5.4 (Medium)
SSVC
Exploitation: none
Automatable: no
Technical Impact: partial
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-07-31 17:01 UTC
CWE
- CWE-862 - Missing Authorization
Assigner
References
5 references
Impacted products
1 product
| Vendor | Product | Version | |
|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Affected:
9.3 , < 9.17
(custom)
|
Credits
{
"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-17351 (GCVE-0-2026-17351)
Vulnerability from cvelistv5 – Published: 2026-07-31 16:00 – Updated: 2026-08-01 03:56
VLAI
EPSS
VEX
Title
pgAdmin 4: AI Assistant read-only transaction bypass via sqlparse/PostgreSQL lexer disagreement (incomplete fix for CVE-2026-12045)
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.
Severity
9 (Critical)
SSVC
Exploitation: none
Automatable: no
Technical Impact: total
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-07-31 00:00 UTC
CWE
Assigner
References
3 references
| URL | Tags |
|---|---|
| https://github.com/pgadmin-org/pgadmin4/issues/10192 | issue-tracking |
| https://github.com/pgadmin-org/pgadmin4/commit/ef… | patch |
| https://github.com/pgadmin-org/pgadmin4/commit/bf… | related |
Impacted products
1 product
| Vendor | Product | Version | |
|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Affected:
9.13 , < 9.17
(custom)
|
Credits
{
"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-17566 (GCVE-0-2026-17566)
Vulnerability from cvelistv5 – Published: 2026-07-31 16:00 – Updated: 2026-08-01 03:56
VLAI
EPSS
VEX
Title
pgAdmin 4: RCE via backslash-escape mismatch in Import/Export Data query guard (incomplete defense, sibling gap to CVE-2025-13780)
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.
Severity
9.9 (Critical)
SSVC
Exploitation: none
Automatable: no
Technical Impact: total
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-07-31 00:00 UTC
CWE
Assigner
References
2 references
| URL | Tags |
|---|---|
| https://github.com/pgadmin-org/pgadmin4/issues/10213 | issue-tracking |
| https://github.com/pgadmin-org/pgadmin4/commit/14… | patch |
Impacted products
1 product
| Vendor | Product | Version | |
|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Affected:
0 , < 9.18
(custom)
|
{
"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"
}
Loading…
Trend slope:
-
(linear fit over daily sighting counts)
Show additional events:
Loading…
Experimental. This forecast is provided for visualization only and may change without notice. Do not use it for operational decisions.
Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Loading…
Loading…
The MITRE ATT&CK techniques below are AI-generated suggestions, inferred from the description of the
vulnerability by the CIRCL/vulnerability-attack-technique-classification-roberta-base
model, served locally by ML-Gateway.
They have not been verified by an analyst and are provided for guidance only.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Loading…
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.
Loading…
Loading…