CVE-2026-12048: pgAdmin 4: Stored XSS enables full browser session hijack

CRITICAL
Published June 18, 2026
CISO Take

pgAdmin 4 versions 6.0 through 9.15 contain a stored cross-site scripting vulnerability where PostgreSQL server-returned text—error messages, EXPLAIN plan node fields, and any object name a low-privilege database user can create—flows unescaped through html-react-parser into more than 50 UI rendering sinks, giving an attacker-controlled database server direct code execution in the admin's browser within pgAdmin's own origin. The CVSS 9.3 critical score reflects a Changed scope: because the injected iframe operates inside pgAdmin's legitimate origin, X-Frame-Options and Content-Security-Policy frame-ancestors controls provide zero protection, and the phishing page rendered inside pgAdmin's window is visually indistinguishable from a real dialog. No public exploit exists yet and the CVE is not in CISA KEV, but attack complexity is Low and no privileges on pgAdmin itself are required—only the ability to write a table or column name to any PostgreSQL server the admin connects to, a bar easily met in shared development databases common in AI/ML teams using pgvector or PostgreSQL-backed RAG stores. Upgrade to pgAdmin 4 9.16 immediately; no effective workaround exists short of restricting pgAdmin connections to fully trusted, access-controlled PostgreSQL servers.

Sources: NVD GitHub Advisory ATLAS

What is the risk?

Critical. CVSS 9.3 with network reachability, low attack complexity, no attacker privileges required on pgAdmin, and Changed scope places this in the top tier of web application vulnerabilities. The exploitation bar is unusually low for a critical-rated CVE: any database user with CREATE TABLE or CREATE COLUMN privileges on any server the victim's pgAdmin connects to can trigger the attack. AI/ML teams are especially exposed because they routinely share PostgreSQL instances for vector stores, embedding tables, and experiment metadata, where many users hold write permissions. The absence of a public exploit and KEV listing modestly reduces near-term exploitation probability, but the vulnerability class (Stored XSS with no viable CSP mitigation path) is well understood by red teams, and the patch commit is public—weaponization via diff analysis is straightforward. pgAdmin's own LLM integration module was confirmed among the ~50 callers patched, underscoring that this tool is actively deployed in AI workflows.

How does the attack unfold?

Initial Poisoning
Attacker with low-privilege database write access creates a PostgreSQL object (table or column) with a name containing an XSS payload, or operates a rogue PostgreSQL server configured to return crafted error messages.
AML.T0049
Trigger via Admin Action
A pgAdmin administrator connects to the poisoned server or runs an EXPLAIN plan on a query referencing the crafted object, causing pgAdmin to receive and pass the malicious text to its rendering pipeline.
AML.T0011
XSS Execution in pgAdmin DOM
html-react-parser renders the unescaped payload at one of 50+ vulnerable UI sinks (notifier toasts, Explain visualiser, form error fields), injecting an iframe into pgAdmin's DOM within its legitimate browser origin where CSP frame-ancestors offers no protection.
AML.T0078
Session Hijack and Credential Exfiltration
The iframe loads attacker-served JavaScript, exfiltrates stored PostgreSQL connection credentials and session tokens, and redirects the admin's tab to an indistinguishable phishing page to harvest further credentials for all registered database servers.
AML.T0052

What systems are affected?

Package Ecosystem Vulnerable Range Patched
pgAdmin 4 No patch

Do you use pgAdmin 4? You're affected.

How severe is it?

CVSS 3.1
9.3 / 10
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
Trivial

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC Low
PR None
UI Required
S Changed
C High
I High
A None

What should I do?

6 steps
  1. Patch immediately: upgrade pgAdmin 4 to version 9.16 or later, which applies DOMPurify sanitization at all html-react-parser call sites, introduces SafeMessage/SafeHtmlMessage plain-text rendering components migrating ~50 callers, and adds backend HTML-escaping via sanitize_external_text in post-connection handlers plus _.escape on Explain plan fields.

  2. While patching, restrict pgAdmin connections to PostgreSQL servers where all users are trusted and object naming is controlled; do not connect pgAdmin to shared development, external, or multi-tenant databases.

  3. Expose pgAdmin only to specific admin IP ranges via firewall or network ACL—never publicly.

  4. Monitor browser sessions accessing pgAdmin for unexpected external requests or navigations; enterprise DLP or browser extension CSP policies can flag iframe injections from unexpected origins.

  5. Audit all pgAdmin server registrations and revoke unnecessary connections to external or shared PostgreSQL instances.

  6. Review access controls on shared PostgreSQL databases used for AI/ML workloads to ensure low-privilege users cannot create arbitrarily named objects.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Art. 15 - Accuracy, Robustness and Cybersecurity
ISO 42001
A.6.1 - AI system life cycle
NIST AI RMF
MANAGE 4.1 - Remediation of identified AI risks
OWASP LLM Top 10
LLM06 - Sensitive Information Disclosure

Frequently Asked Questions

What is CVE-2026-12048?

pgAdmin 4 versions 6.0 through 9.15 contain a stored cross-site scripting vulnerability where PostgreSQL server-returned text—error messages, EXPLAIN plan node fields, and any object name a low-privilege database user can create—flows unescaped through html-react-parser into more than 50 UI rendering sinks, giving an attacker-controlled database server direct code execution in the admin's browser within pgAdmin's own origin. The CVSS 9.3 critical score reflects a Changed scope: because the injected iframe operates inside pgAdmin's legitimate origin, X-Frame-Options and Content-Security-Policy frame-ancestors controls provide zero protection, and the phishing page rendered inside pgAdmin's window is visually indistinguishable from a real dialog. No public exploit exists yet and the CVE is not in CISA KEV, but attack complexity is Low and no privileges on pgAdmin itself are required—only the ability to write a table or column name to any PostgreSQL server the admin connects to, a bar easily met in shared development databases common in AI/ML teams using pgvector or PostgreSQL-backed RAG stores. Upgrade to pgAdmin 4 9.16 immediately; no effective workaround exists short of restricting pgAdmin connections to fully trusted, access-controlled PostgreSQL servers.

Is CVE-2026-12048 actively exploited?

No confirmed active exploitation of CVE-2026-12048 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-12048?

1. Patch immediately: upgrade pgAdmin 4 to version 9.16 or later, which applies DOMPurify sanitization at all html-react-parser call sites, introduces SafeMessage/SafeHtmlMessage plain-text rendering components migrating ~50 callers, and adds backend HTML-escaping via sanitize_external_text in post-connection handlers plus _.escape on Explain plan fields. 2. While patching, restrict pgAdmin connections to PostgreSQL servers where all users are trusted and object naming is controlled; do not connect pgAdmin to shared development, external, or multi-tenant databases. 3. Expose pgAdmin only to specific admin IP ranges via firewall or network ACL—never publicly. 4. Monitor browser sessions accessing pgAdmin for unexpected external requests or navigations; enterprise DLP or browser extension CSP policies can flag iframe injections from unexpected origins. 5. Audit all pgAdmin server registrations and revoke unnecessary connections to external or shared PostgreSQL instances. 6. Review access controls on shared PostgreSQL databases used for AI/ML workloads to ensure low-privilege users cannot create arbitrarily named objects.

What systems are affected by CVE-2026-12048?

This vulnerability affects the following AI/ML architecture patterns: RAG pipelines, vector databases, ML data infrastructure, AI development environments, model serving.

What is the CVSS score for CVE-2026-12048?

CVE-2026-12048 has a CVSS v3.1 base score of 9.3 (CRITICAL).

What is the AI security impact?

Affected AI Architectures

RAG pipelinesvector databasesML data infrastructureAI development environmentsmodel serving

MITRE ATLAS Techniques

AML.T0011 User Execution
AML.T0049 Exploit Public-Facing Application
AML.T0052 Phishing
AML.T0078 Drive-by Compromise

Compliance Controls Affected

EU AI Act: Art. 15
ISO 42001: A.6.1
NIST AI RMF: MANAGE 4.1
OWASP LLM Top 10: LLM06

What are the technical details?

Original Advisory

Stored cross-site scripting in pgAdmin 4's error-rendering and plan-node-rendering paths. Text returned by a PostgreSQL server (ErrorResponse messages, including object names quoted back inside relation-does-not-exist errors and inside EXPLAIN Recheck Cond / Exact Heap Blocks fields) was passed verbatim through html-react-parser at every user-facing sink — the notifier toasts, FormFooterMessage / FormInput help and error areas, FormNote, ModalProvider AlertContent and confirmDelete, ToolErrorView, the Explain visualiser's NodeText panel, the SQL editor confirm dialogs, ConfirmSaveContent, PreferencesHelper modal alerts, and SelectThemes helper text. A PostgreSQL server an attacker controls — or any server returning attacker-influenced text such as a table or column name a low-privilege database user can create — could inject arbitrary HTML (including <iframe>) into the pgAdmin DOM the moment the victim's pgAdmin connected to that server or viewed an Explain plan that referenced the crafted object. The injected iframe's srcdoc could fetch attacker-served JavaScript and, by writing to parent.location, redirect the victim's top-level pgAdmin browser tab to an attacker-controlled URL. Because the injection originates from inside pgAdmin's own interface, standard anti-clickjacking controls (X-Frame-Options, Content-Security-Policy: frame-ancestors) do not mitigate it. A phishing page rendered inside the legitimate pgAdmin window is indistinguishable from a genuine pgAdmin dialog. Fix combines three complementary layers. (1) DOMPurify sanitisation is wrapped around every html-react-parser call site reachable from notifier, alert, form-error, Explain, and SQL-editor flows. (2) A new plain-text rendering contract — SafeMessage / SafeHtmlMessage components plus Notifier.errorText / alertText / warningText / infoText / successText helpers — is introduced; around fifty callers across browser, tools, dashboard, debugger, misc, llm, preferences, schema diff, and the SQL editor that previously interpolated backend-derived strings are migrated to the plain-text variants. (3) Backend HTML-escape is applied at the post-connection-SQL handler (execute_post_connection_sql) via a new sanitize_external_text helper, so third-party JSON consumers (audit logs, API clients) never receive raw markup either; the Explain plan-info renderer is also patched to _.escape Recheck Cond and Exact Heap Blocks at construction (matching every sibling field), giving defence in depth even before DOMPurify runs. This issue affects pgAdmin 4: from 6.0 before 9.16.

Exploitation Scenario

An attacker with INSERT privilege on a shared PostgreSQL database used as a pgvector RAG store creates a table named with an embedded XSS payload: a name containing an iframe whose srcdoc attribute loads attacker-served JavaScript. When the DBA opens pgAdmin and executes any query that causes PostgreSQL to reference this table in a relation-does-not-exist error—routine during schema exploration or debugging—pgAdmin's notifier toast renders the table name verbatim via html-react-parser. The iframe loads attacker JavaScript inside pgAdmin's own origin: it reads the pgAdmin master password store and browser-stored credentials, exfiltrates connection strings for all registered servers (including production pgvector instances), and calls parent.location to replace the pgAdmin tab with an indistinguishable phishing login page. In an AI/ML context, this attack is trivially triggered during routine maintenance—running EXPLAIN ANALYZE on a vector similarity search query or browsing an embedding table in the schema browser—with no visual indication to the victim that anything malicious occurred.

Weaknesses (CWE)

CWE-116 — Improper Encoding or Escaping of Output: The product prepares a structured message for communication with another component, but encoding or escaping of the data is either missing or done incorrectly. As a result, the intended structure of the message is not preserved.

  • [Architecture and Design] Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid. For example, consider using the ESAPI Encoding control [REF-45] or a similar tool, library, or framework. These will help the programmer encode outputs in a manner less prone to error. Alternately, use built-in functions, but consider using wrappers in case those functions are discovered to have a vulnerability.
  • [Architecture and Design] If available, use structured mechanisms that automatically enforce the separation between data and code. These mechanisms may be able to provide the relevant quoting, encoding, and validation automatically, instead of relying on the developer to provide this capability at every point where output is generated. For example, stored procedures can enforce database query structure and reduce the likelihood of SQL injection.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N

Timeline

Published
June 18, 2026
Last Modified
June 19, 2026
First Seen
June 19, 2026

Related Vulnerabilities