CVE-2026-12047 (GCVE-0-2026-12047)
Vulnerability from cvelistv5 – Published: 2026-06-18 23:37 – Updated: 2026-06-22 19:14
VLAI
EPSS
VEX
Title
pgAdmin 4: HTML injection in cloud verify_credentials / deploy endpoints via unsanitised SDK exception text
Summary
HTML injection in pgAdmin 4's cloud deployment module. The verify_credentials, deploy, regions, and update-server endpoints under /rds/, /azure/, /google/, and the top-level /cloud/ blueprint propagated AWS / Azure / Google SDK exception text — and the related file-resolution and database-commit exception text — into the JSON response body (the info and errormsg fields) without HTML-encoding. The Cloud Wizard frontend rendered these strings through html-react-parser, so an attacker-influenced exception message embedded structural HTML directly into the wizard's DOM.
The reported entry point is /rds/verify_credentials/. An authenticated pgAdmin user submits a crafted access_key whose value contains an <iframe/src=...> payload; AWS STS rejects the credential with an IncompleteSignature exception whose text quotes the access_key verbatim; the pgAdmin backend forwards that text into the JSON info field; the Cloud Wizard's FormFooterMessage parses it as HTML. The browser fetches the iframe's src from an attacker-controlled host, and JavaScript executing inside the cross-origin iframe writes to parent.location, redirecting the victim's pgAdmin tab. Because the injection renders inside pgAdmin's own interface, X-Frame-Options and Content-Security-Policy frame-ancestors do not mitigate it. Baseline impact is self-targeted (the same user who supplied the payload sees the injection); escalation against other authenticated users requires an additional cross-site request-forgery primitive capable of submitting the malformed credential request with a valid X-pgA-CSRFToken in the victim's browser context.
The same unsanitised-error-into-JSON pattern was present across multiple sibling endpoints — Azure's check_cluster_name_availability, every Google endpoint that surfaces SDK errors (verification_ack, projects, regions, instance_types, database_versions, the verify_credentials path-resolution branches), the central /deploy endpoint that bubbles str(e) from deploy_on_rds / deploy_on_azure / deploy_on_google, and update_cloud_server which surfaces the str(e) from a failing db.session.commit — all of which are now covered.
Fix HTML-escapes every external/SDK exception string at the endpoint sink via a new shared sanitize_external_text helper (HTML escape with control-character strip), promoted out of the psycopg3 driver into web/pgadmin/utils/text_sanitize.py. The Cloud Wizard frontend additionally renders its FormFooterMessage in plain-text mode for backend-derived strings, so the value is never parsed as HTML even if a future sink forgets the escape.
This issue affects pgAdmin 4: from 6.6 before 9.16.
Severity
SSVC
Exploitation: none
Automatable: no
Technical Impact: partial
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-06-22 19:13 UTC
CWE
Assigner
References
2 references
| URL | Tags |
|---|---|
| https://github.com/pgadmin-org/pgadmin4/issues/10069 | issue-tracking |
| https://github.com/pgadmin-org/pgadmin4/commit/60… | patch |
Impacted products
1 product
| Vendor | Product | Version | CPE status | |
|---|---|---|---|---|
| pgadmin.org | pgAdmin 4 |
Affected:
6.6 , < 9.16
(custom)
|
guessed |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-12047",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-22T19:13:58.685569Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-22T19:14:24.816Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Cloud Deployment",
"Cloud RDS",
"Cloud Azure",
"Cloud Google"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/rds/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/azure/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/google/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/static/js/CloudWizard.jsx"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.16",
"status": "affected",
"version": "6.6",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Fernando Bortotti \u003cfernando.bortotti@bsd.com.br\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "HTML injection in pgAdmin 4\u0027s cloud deployment module. The verify_credentials, deploy, regions, and update-server endpoints under /rds/, /azure/, /google/, and the top-level /cloud/ blueprint propagated AWS / Azure / Google SDK exception text \u2014 and the related file-resolution and database-commit exception text \u2014 into the JSON response body (the info and errormsg fields) without HTML-encoding. The Cloud Wizard frontend rendered these strings through html-react-parser, so an attacker-influenced exception message embedded structural HTML directly into the wizard\u0027s DOM.\n\nThe reported entry point is /rds/verify_credentials/. An authenticated pgAdmin user submits a crafted access_key whose value contains an \u003ciframe/src=...\u003e payload; AWS STS rejects the credential with an IncompleteSignature exception whose text quotes the access_key verbatim; the pgAdmin backend forwards that text into the JSON info field; the Cloud Wizard\u0027s FormFooterMessage parses it as HTML. The browser fetches the iframe\u0027s src from an attacker-controlled host, and JavaScript executing inside the cross-origin iframe writes to parent.location, redirecting the victim\u0027s pgAdmin tab. Because the injection renders inside pgAdmin\u0027s own interface, X-Frame-Options and Content-Security-Policy frame-ancestors do not mitigate it. Baseline impact is self-targeted (the same user who supplied the payload sees the injection); escalation against other authenticated users requires an additional cross-site request-forgery primitive capable of submitting the malformed credential request with a valid X-pgA-CSRFToken in the victim\u0027s browser context.\n\nThe same unsanitised-error-into-JSON pattern was present across multiple sibling endpoints \u2014 Azure\u0027s check_cluster_name_availability, every Google endpoint that surfaces SDK errors (verification_ack, projects, regions, instance_types, database_versions, the verify_credentials path-resolution branches), the central /deploy endpoint that bubbles str(e) from deploy_on_rds / deploy_on_azure / deploy_on_google, and update_cloud_server which surfaces the str(e) from a failing db.session.commit \u2014 all of which are now covered.\n\nFix HTML-escapes every external/SDK exception string at the endpoint sink via a new shared sanitize_external_text helper (HTML escape with control-character strip), promoted out of the psycopg3 driver into web/pgadmin/utils/text_sanitize.py. The Cloud Wizard frontend additionally renders its FormFooterMessage in plain-text mode for backend-derived strings, so the value is never parsed as HTML even if a future sink forgets the escape.\n\nThis issue affects pgAdmin 4: from 6.6 before 9.16."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 3.5,
"baseSeverity": "LOW",
"confidentialityImpact": "NONE",
"integrityImpact": "LOW",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Self-XSS only. The same authenticated pgAdmin user that submits the crafted cloud credential is the one whose browser renders the echoed error -- there is no third-party attacker driving a distinct victim, so the confused-deputy elements (S:C / C:H confidentiality uplift) do not apply. The frontend DOMPurify layer added by #10068 already neutralises the in-browser exploit; this fix is defence in depth that ensures non-browser JSON consumers (audit logs, scripted API clients) never see the raw markup either. Scored as I:L for that residual escape only; S:U because no authority is crossed.\n\nCross-user escalation would require an independent CSRF primitive capable of submitting the malformed credential request with a valid X-pgA-CSRFToken in the victim\u0027s browser context. That is not part of this defect."
}
]
},
{
"cvssV4_0": {
"baseScore": 4.8,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as CVSS 3.1 -- self-XSS, no third-party attacker, no scope change. VI:L for the defence-in-depth backend escape that prevents the raw markup from reaching non-browser API consumers; no other impact."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-79",
"description": "CWE-79 Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-116",
"description": "CWE-116 Improper Encoding or Escaping of Output",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-18T23:37:39.657Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10069"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/60d149864b5fdd99675754c7996637737a24fce3"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: HTML injection in cloud verify_credentials / deploy endpoints via unsanitised SDK exception text"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-12047",
"datePublished": "2026-06-18T23:37:39.657Z",
"dateReserved": "2026-06-11T20:40:07.824Z",
"dateUpdated": "2026-06-22T19:14:24.816Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"vulnerability-lookup:meta": {
"epss": {
"cve": "CVE-2026-12047",
"date": "2026-10-31",
"epss": "0.00221",
"percentile": "0.12678"
},
"nvd": {
"cve": {
"affected": [
{
"affectedData": [
{
"defaultStatus": "unaffected",
"modules": [
"Cloud Deployment",
"Cloud RDS",
"Cloud Azure",
"Cloud Google"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/rds/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/azure/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/google/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/static/js/CloudWizard.jsx"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.16",
"status": "affected",
"version": "6.6",
"versionType": "custom"
}
]
}
],
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007"
}
],
"configurations": [
{
"nodes": [
{
"cpeMatch": [
{
"criteria": "cpe:2.3:a:pgadmin:pgadmin_4:*:*:*:*:*:postgresql:*:*",
"matchCriteriaId": "BC047297-CF61-4536-AA24-CBA6439EA155",
"versionEndExcluding": "9.16",
"versionStartIncluding": "6.6",
"vulnerable": true
}
],
"negate": false,
"operator": "OR"
}
]
}
],
"cveTags": [],
"descriptions": [
{
"lang": "en",
"value": "HTML injection in pgAdmin 4\u0027s cloud deployment module. The verify_credentials, deploy, regions, and update-server endpoints under /rds/, /azure/, /google/, and the top-level /cloud/ blueprint propagated AWS / Azure / Google SDK exception text \u2014 and the related file-resolution and database-commit exception text \u2014 into the JSON response body (the info and errormsg fields) without HTML-encoding. The Cloud Wizard frontend rendered these strings through html-react-parser, so an attacker-influenced exception message embedded structural HTML directly into the wizard\u0027s DOM.\n\nThe reported entry point is /rds/verify_credentials/. An authenticated pgAdmin user submits a crafted access_key whose value contains an \u003ciframe/src=...\u003e payload; AWS STS rejects the credential with an IncompleteSignature exception whose text quotes the access_key verbatim; the pgAdmin backend forwards that text into the JSON info field; the Cloud Wizard\u0027s FormFooterMessage parses it as HTML. The browser fetches the iframe\u0027s src from an attacker-controlled host, and JavaScript executing inside the cross-origin iframe writes to parent.location, redirecting the victim\u0027s pgAdmin tab. Because the injection renders inside pgAdmin\u0027s own interface, X-Frame-Options and Content-Security-Policy frame-ancestors do not mitigate it. Baseline impact is self-targeted (the same user who supplied the payload sees the injection); escalation against other authenticated users requires an additional cross-site request-forgery primitive capable of submitting the malformed credential request with a valid X-pgA-CSRFToken in the victim\u0027s browser context.\n\nThe same unsanitised-error-into-JSON pattern was present across multiple sibling endpoints \u2014 Azure\u0027s check_cluster_name_availability, every Google endpoint that surfaces SDK errors (verification_ack, projects, regions, instance_types, database_versions, the verify_credentials path-resolution branches), the central /deploy endpoint that bubbles str(e) from deploy_on_rds / deploy_on_azure / deploy_on_google, and update_cloud_server which surfaces the str(e) from a failing db.session.commit \u2014 all of which are now covered.\n\nFix HTML-escapes every external/SDK exception string at the endpoint sink via a new shared sanitize_external_text helper (HTML escape with control-character strip), promoted out of the psycopg3 driver into web/pgadmin/utils/text_sanitize.py. The Cloud Wizard frontend additionally renders its FormFooterMessage in plain-text mode for backend-derived strings, so the value is never parsed as HTML even if a future sink forgets the escape.\n\nThis issue affects pgAdmin 4: from 6.6 before 9.16."
},
{
"lang": "es",
"value": "Inyecci\u00f3n HTML en el m\u00f3dulo de despliegue en la nube de pgAdmin 4. Los puntos finales verify_credentials, deploy, regions y update-server bajo /rds/, /azure/, /google/ y el esquema de nivel superior /cloud/ propagaron texto de excepci\u00f3n del SDK de AWS / Azure / Google - y el texto de excepci\u00f3n relacionado con la resoluci\u00f3n de archivos y la confirmaci\u00f3n de la base de datos - en el cuerpo de la respuesta JSON (los campos info y errormsg) sin codificaci\u00f3n HTML. El frontend del Asistente de la Nube renderiz\u00f3 estas cadenas a trav\u00e9s de html-react-parser, por lo que un mensaje de excepci\u00f3n influenciado por el atacante incrust\u00f3 HTML estructural directamente en el DOM del asistente.\n\nEl punto de entrada reportado es /rds/verify_credentials/. Un usuario autenticado de pgAdmin env\u00eda una access_key manipulada cuyo valor contiene una carga \u00fatil [iframe_tag]; AWS STS rechaza la credencial con una excepci\u00f3n IncompleteSignature cuyo texto cita la access_key textualmente; el backend de pgAdmin reenv\u00eda ese texto al campo JSON info; el FormFooterMessage del Asistente de la Nube lo analiza como HTML. El navegador obtiene el src del iframe de un host controlado por el atacante, y JavaScript ejecut\u00e1ndose dentro del iframe de origen cruzado escribe en parent.location, redirigiendo la pesta\u00f1a de pgAdmin de la v\u00edctima. Debido a que la inyecci\u00f3n se renderiza dentro de la propia interfaz de pgAdmin, X-Frame-Options y Content-Security-Policy frame-ancestors no lo mitigan. El impacto base es auto-dirigido (el mismo usuario que proporcion\u00f3 la carga \u00fatil ve la inyecci\u00f3n); la escalada contra otros usuarios autenticados requiere una primitiva adicional de falsificaci\u00f3n de solicitud entre sitios capaz de enviar la solicitud de credencial malformada con un X-pgA-CSRFToken v\u00e1lido en el contexto del navegador de la v\u00edctima.\n\nEl mismo patr\u00f3n de error no saneado en JSON estaba presente en m\u00faltiples puntos finales hermanos - check_cluster_name_availability de Azure, cada punto final de Google que muestra errores del SDK (verification_ack, projects, regions, instance_types, database_versions, las ramas de resoluci\u00f3n de ruta de verify_credentials), el punto final central /deploy que propaga str(e) de deploy_on_rds / deploy_on_azure / deploy_on_google, y update_cloud_server que muestra el str(e) de un db.session.commit fallido - todos los cuales ahora est\u00e1n cubiertos.\n\nSe corrige el escape HTML de cada cadena de excepci\u00f3n externa/del SDK en el sumidero del punto final a trav\u00e9s de un nuevo ayudante compartido sanitize_external_text (escape HTML con eliminaci\u00f3n de caracteres de control), promovido del controlador psycopg3 a web/pgadmin/utils/text_sanitize.py. El frontend del Asistente de la Nube adicionalmente renderiza su FormFooterMessage en modo de texto plano para cadenas derivadas del backend, por lo que el valor nunca se analiza como HTML incluso si un futuro sumidero olvida el escape.\n\nEste problema afecta a pgAdmin 4: desde 6.6 antes de 9.16."
}
],
"id": "CVE-2026-12047",
"lastModified": "2026-10-26T11:10:00.157",
"metrics": {
"cvssMetricV31": [
{
"cvssData": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 3.5,
"baseSeverity": "LOW",
"confidentialityImpact": "NONE",
"integrityImpact": "LOW",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N",
"version": "3.1"
},
"exploitabilityScore": 2.1,
"impactScore": 1.4,
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"type": "Secondary"
},
{
"cvssData": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 5.4,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "LOW",
"integrityImpact": "LOW",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N",
"version": "3.1"
},
"exploitabilityScore": 2.3,
"impactScore": 2.7,
"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": 4.8,
"baseSeverity": "MEDIUM",
"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": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "NONE",
"userInteraction": "ACTIVE",
"valueDensity": "NOT_DEFINED",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/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": "NONE",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "LOW",
"vulnerabilityResponseEffort": "NOT_DEFINED"
},
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"type": "Secondary"
}
],
"ssvcV203": [
{
"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"ssvcData": {
"id": "CVE-2026-12047",
"options": [
{
"exploitation": "none"
},
{
"automatable": "no"
},
{
"technicalImpact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-22T19:13:58.685569Z",
"version": "2.0.3"
}
}
]
},
"published": "2026-06-19T00:16:47.040",
"references": [
{
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"tags": [
"Patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/60d149864b5fdd99675754c7996637737a24fce3"
},
{
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"tags": [
"Issue Tracking",
"Patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10069"
}
],
"sourceIdentifier": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"vulnStatus": "Analyzed",
"weaknesses": [
{
"description": [
{
"lang": "en",
"value": "CWE-79"
},
{
"lang": "en",
"value": "CWE-116"
}
],
"source": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"type": "Secondary"
},
{
"description": [
{
"lang": "en",
"value": "CWE-79"
}
],
"source": "nvd@nist.gov",
"type": "Primary"
}
]
}
},
"redhat_vex": {
"current_release_date": "2026-06-28T11:03:05+00:00",
"cve": "CVE-2026-12047",
"id": "CVE-2026-12047",
"initial_release_date": "2026-06-18T23:37:39.657000+00:00",
"product_status:known_not_affected": "1",
"source": "Red Hat CSAF VEX",
"status": "final",
"title": "pgadmin4: pgAdmin 4: HTML injection via unsanitized SDK exception messages in cloud deployment module",
"url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-12047.json",
"version": "3"
},
"vulnrichment": {
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-12047",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-22T19:13:58.685569Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-22T19:14:20.566Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"modules": [
"Cloud Deployment",
"Cloud RDS",
"Cloud Azure",
"Cloud Google"
],
"product": "pgAdmin 4",
"programFiles": [
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/rds/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/azure/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/google/__init__.py",
"https://github.com/pgadmin-org/pgadmin4/blob/master/web/pgadmin/misc/cloud/static/js/CloudWizard.jsx"
],
"repo": "https://github.com/pgadmin-org/pgadmin4",
"vendor": "pgadmin.org",
"versions": [
{
"lessThan": "9.16",
"status": "affected",
"version": "6.6",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Fernando Bortotti \u003cfernando.bortotti@bsd.com.br\u003e"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Ashesh Vashi \u003cashesh.vashi@enterprisedb.com\u003e"
}
],
"descriptions": [
{
"lang": "en",
"value": "HTML injection in pgAdmin 4\u0027s cloud deployment module. The verify_credentials, deploy, regions, and update-server endpoints under /rds/, /azure/, /google/, and the top-level /cloud/ blueprint propagated AWS / Azure / Google SDK exception text \u2014 and the related file-resolution and database-commit exception text \u2014 into the JSON response body (the info and errormsg fields) without HTML-encoding. The Cloud Wizard frontend rendered these strings through html-react-parser, so an attacker-influenced exception message embedded structural HTML directly into the wizard\u0027s DOM.\n\nThe reported entry point is /rds/verify_credentials/. An authenticated pgAdmin user submits a crafted access_key whose value contains an \u003ciframe/src=...\u003e payload; AWS STS rejects the credential with an IncompleteSignature exception whose text quotes the access_key verbatim; the pgAdmin backend forwards that text into the JSON info field; the Cloud Wizard\u0027s FormFooterMessage parses it as HTML. The browser fetches the iframe\u0027s src from an attacker-controlled host, and JavaScript executing inside the cross-origin iframe writes to parent.location, redirecting the victim\u0027s pgAdmin tab. Because the injection renders inside pgAdmin\u0027s own interface, X-Frame-Options and Content-Security-Policy frame-ancestors do not mitigate it. Baseline impact is self-targeted (the same user who supplied the payload sees the injection); escalation against other authenticated users requires an additional cross-site request-forgery primitive capable of submitting the malformed credential request with a valid X-pgA-CSRFToken in the victim\u0027s browser context.\n\nThe same unsanitised-error-into-JSON pattern was present across multiple sibling endpoints \u2014 Azure\u0027s check_cluster_name_availability, every Google endpoint that surfaces SDK errors (verification_ack, projects, regions, instance_types, database_versions, the verify_credentials path-resolution branches), the central /deploy endpoint that bubbles str(e) from deploy_on_rds / deploy_on_azure / deploy_on_google, and update_cloud_server which surfaces the str(e) from a failing db.session.commit \u2014 all of which are now covered.\n\nFix HTML-escapes every external/SDK exception string at the endpoint sink via a new shared sanitize_external_text helper (HTML escape with control-character strip), promoted out of the psycopg3 driver into web/pgadmin/utils/text_sanitize.py. The Cloud Wizard frontend additionally renders its FormFooterMessage in plain-text mode for backend-derived strings, so the value is never parsed as HTML even if a future sink forgets the escape.\n\nThis issue affects pgAdmin 4: from 6.6 before 9.16."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 3.5,
"baseSeverity": "LOW",
"confidentialityImpact": "NONE",
"integrityImpact": "LOW",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Self-XSS only. The same authenticated pgAdmin user that submits the crafted cloud credential is the one whose browser renders the echoed error -- there is no third-party attacker driving a distinct victim, so the confused-deputy elements (S:C / C:H confidentiality uplift) do not apply. The frontend DOMPurify layer added by #10068 already neutralises the in-browser exploit; this fix is defence in depth that ensures non-browser JSON consumers (audit logs, scripted API clients) never see the raw markup either. Scored as I:L for that residual escape only; S:U because no authority is crossed.\n\nCross-user escalation would require an independent CSRF primitive capable of submitting the malformed credential request with a valid X-pgA-CSRFToken in the victim\u0027s browser context. That is not part of this defect."
}
]
},
{
"cvssV4_0": {
"baseScore": 4.8,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
"version": "4.0"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "Same reasoning as CVSS 3.1 -- self-XSS, no third-party attacker, no scope change. VI:L for the defence-in-depth backend escape that prevents the raw markup from reaching non-browser API consumers; no other impact."
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-79",
"description": "CWE-79 Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-116",
"description": "CWE-116 Improper Encoding or Escaping of Output",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-18T23:37:39.657Z",
"orgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"shortName": "PostgreSQL"
},
"references": [
{
"tags": [
"issue-tracking"
],
"url": "https://github.com/pgadmin-org/pgadmin4/issues/10069"
},
{
"tags": [
"patch"
],
"url": "https://github.com/pgadmin-org/pgadmin4/commit/60d149864b5fdd99675754c7996637737a24fce3"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "pgAdmin 4: HTML injection in cloud verify_credentials / deploy endpoints via unsanitised SDK exception text"
}
},
"cveMetadata": {
"assignerOrgId": "f86ef6dc-4d3a-42ad-8f28-e6d5547a5007",
"assignerShortName": "PostgreSQL",
"cveId": "CVE-2026-12047",
"datePublished": "2026-06-18T23:37:39.657Z",
"dateReserved": "2026-06-11T20:40:07.824Z",
"dateUpdated": "2026-06-22T19:14:24.816Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
}
}
Loading…
Loading…
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.
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.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
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.