FKIE_CVE-2026-17351
Vulnerability from fkie_nvd - Published: 2026-07-31 16:16 - Updated: 2026-10-23 23:109.0 (Critical) - CVSS:3.1/
{
"affected": [
{
"affectedData": [
{
"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"
}
]
}
],
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007"
}
],
"configurations": [
{
"nodes": [
{
"cpeMatch": [
{
"criteria": "cpe:2.3:a:pgadmin:pgadmin_4:*:*:*:*:*:postgresql:*:*",
"matchCriteriaId": "DA305ECD-4B65-4A51-8E65-4C7BD39105F4",
"versionEndExcluding": "9.17",
"versionStartIncluding": "9.13",
"vulnerable": true
}
],
"negate": false,
"operator": "OR"
}
]
}
],
"cveTags": [],
"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."
},
{
"lang": "es",
"value": "La soluci\u00f3n para CVE-2026-12045 en pgAdmin 4 9.16 requer\u00eda que la consulta proporcionada por el LLM, pasada a la herramienta execute_sql_query del Asistente de IA, se analizara, a trav\u00e9s de sqlparse, como exactamente una declaraci\u00f3n que no fuera de control de transacciones antes de ejecutarla dentro de un envoltorio BEGIN TRANSACTION READ ONLY. El an\u00e1lisis l\u00e9xico de literales de cadena de sqlparse puede diferir del propio analizador de PostgreSQL: bajo standard_conforming_strings = on (el valor predeterminado de PostgreSQL desde la versi\u00f3n 9.1), una barra invertida inmediatamente antes de una comilla es un car\u00e1cter ordinario para PostgreSQL, pero sqlparse la trata como un escape de la comilla. Una carga \u00fatil como SELECT \u2019\\\u2019;COMMIT;CREATE TABLE pwn(x int);SELECT 1 --\u2019 por lo tanto, se analiza como un \u00fanico SELECT para el validador de sqlparse, mientras que PostgreSQL la ejecuta como cuatro declaraciones: el COMMIT introducido de contrabando finaliza la transacci\u00f3n de solo lectura envolvente, y el ROLLBACK final se convierte en una operaci\u00f3n nula. Esto reintroduce el mismo bypass de escritura/RCE que CVE-2026-12045 pretend\u00eda cerrar, alcanzable a trav\u00e9s de la misma entrega indirecta de inyecci\u00f3n de prompt (un atacante planta la carga \u00fatil en cualquier objeto que el Asistente de IA pueda leer; el LLM la emite como una llamada a herramienta).\n\nUna soluci\u00f3n candidata inicial ejecut\u00f3 la consulta con execute(..., prepare=True) de psycopg, con la intenci\u00f3n de forzar el propio paso de Parse de PostgreSQL (protocolo de consulta extendido) para rechazar texto con m\u00faltiples declaraciones independientemente de la clasificaci\u00f3n de sqlparse. Esta soluci\u00f3n candidata no funciona como se envi\u00f3: el PrepareManager de psycopg3 ignora silenciosamente el argumento prepare siempre que el prepare_threshold de la conexi\u00f3n es None, que es el valor predeterminado de pgAdmin para cada conexi\u00f3n de servidor (el campo \u2019Umbral de preparaci\u00f3n\u2019 por servidor est\u00e1 en blanco a menos que un administrador lo configure expl\u00edcitamente) -- psycopg3 recurre al protocolo de consulta simple, la misma ruta capaz de m\u00faltiples declaraciones que explota el bypass, por lo que la soluci\u00f3n candidata no cierra nada en ninguna configuraci\u00f3n predeterminada del mundo real.\n\nLa soluci\u00f3n corregida establece conn.prepare_threshold = 0 directamente en la conexi\u00f3n de solo lectura dedicada y de un solo uso que abre la herramienta del Asistente de IA, forzando estructuralmente el protocolo de consulta extendido independientemente de cualquier configuraci\u00f3n a nivel de servidor. Verificado contra una instancia activa de PostgreSQL 18: la carga \u00fatil se ejecuta correctamente bajo el comportamiento prepare_threshold=None (predeterminado), y es rechazada con \u2019cannot insert multiple commands into a prepared statement\u2019 una vez que prepare_threshold=0 se establece en esa conexi\u00f3n.\n\nEste problema afecta a pgAdmin 4: desde la versi\u00f3n 9.13 hasta antes de la 9.17."
}
],
"id": "CVE-2026-17351",
"lastModified": "2026-10-23T23:10:00.157",
"metrics": {
"cvssMetricV31": [
{
"cvssData": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 9.0,
"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"
},
"exploitabilityScore": 2.3,
"impactScore": 6.0,
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"type": "Secondary"
},
{
"cvssData": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 9.0,
"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"
},
"exploitabilityScore": 2.3,
"impactScore": 6.0,
"source": "nvd@nist.gov",
"type": "Primary"
}
],
"cvssMetricV40": [
{
"cvssData": {
"Automatable": "NOT_DEFINED",
"Recovery": "NOT_DEFINED",
"Safety": "NOT_DEFINED",
"attackComplexity": "LOW",
"attackRequirements": "NONE",
"attackVector": "NETWORK",
"availabilityRequirement": "NOT_DEFINED",
"baseScore": 9.4,
"baseSeverity": "CRITICAL",
"confidentialityRequirement": "NOT_DEFINED",
"exploitMaturity": "NOT_DEFINED",
"integrityRequirement": "NOT_DEFINED",
"modifiedAttackComplexity": "NOT_DEFINED",
"modifiedAttackRequirements": "NOT_DEFINED",
"modifiedAttackVector": "NOT_DEFINED",
"modifiedPrivilegesRequired": "NOT_DEFINED",
"modifiedSubAvailabilityImpact": "NOT_DEFINED",
"modifiedSubConfidentialityImpact": "NOT_DEFINED",
"modifiedSubIntegrityImpact": "NOT_DEFINED",
"modifiedUserInteraction": "NOT_DEFINED",
"modifiedVulnAvailabilityImpact": "NOT_DEFINED",
"modifiedVulnConfidentialityImpact": "NOT_DEFINED",
"modifiedVulnIntegrityImpact": "NOT_DEFINED",
"privilegesRequired": "LOW",
"providerUrgency": "NOT_DEFINED",
"subAvailabilityImpact": "HIGH",
"subConfidentialityImpact": "HIGH",
"subIntegrityImpact": "HIGH",
"userInteraction": "PASSIVE",
"valueDensity": "NOT_DEFINED",
"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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"version": "4.0",
"vulnAvailabilityImpact": "HIGH",
"vulnConfidentialityImpact": "HIGH",
"vulnIntegrityImpact": "HIGH",
"vulnerabilityResponseEffort": "NOT_DEFINED"
},
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"type": "Secondary"
}
],
"ssvcV203": [
{
"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"ssvcData": {
"id": "CVE-2026-17351",
"options": [
{
"exploitation": "none"
},
{
"automatable": "no"
},
{
"technicalImpact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-07-31T00:00:00+00:00",
"version": "2.0.3"
}
}
]
},
"published": "2026-07-31T16:16:59.807",
"references": [
{
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"tags": [
"Patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/bf4792444446f0e7ab721d23cbd6bfe6afaa7a8b"
},
{
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"tags": [
"Patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/ef76102bcd1cdb544eb9b4ef18d3382f22b76752"
},
{
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"tags": [
"Issue Tracking",
"Patch",
"Vendor Advisory"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10192"
}
],
"sourceIdentifier": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"vulnStatus": "Analyzed",
"weaknesses": [
{
"description": [
{
"lang": "en",
"value": "CWE-89"
},
{
"lang": "en",
"value": "CWE-115"
}
],
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"type": "Secondary"
}
]
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
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.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
How durations are calculated
Following the VTEM framework (Black Hat USA 2015), time to patch starts when the vendor or a coordinator was informed, total time to patch at discovery, and disclosure to patch at public disclosure; vendor response time runs from the report to its acknowledgement. Time to exploit and time unpatched start at the earliest discovery or report, falling back to public disclosure. Unpatched time ends at the first recorded patch, or the calculation time when no patch is recorded. Exploitation to patch shows the interval between those two events; a published proof of concept is a public exploit, not exploitation.
Each result shows its source dates. A negative interval means the end event came first; when date-only inputs leave the order open, the result says so. Date-only inputs are approximate. The earliest evidence wins: KEV report dates and sightings are labelled as such. Records describing another vulnerability are listed but never calculated from, and a PoC alone does not establish exploitation. Missing patch evidence does not prove that no patch exists. Filters below change the event list only.
Loading timeline…
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.
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.