/

CVE-2026-17346

Severity:

HIGH RISK

(8.8)

SQL Injection (CWE-89) in pgAdmin 4 statistics views

CVE-2026-17346

Analyzed

Vulnerability type

Category:

SQL Injection

CWE:

CWE-89

Impact:

Arbitrary SQL Execution in Viewer Session

Severity:

HIGH RISK

(8.8)

CVSS version:

3.1

Catch this CVE while code is being written

Detect vulnerable code directly in pull requests, so CVEs are fixed before merge.

Summary

A SQL injection flaw in pgAdmin 4's Statistics and Dependencies views allows unescaped object names to be interpolated directly into SQL templates.

A low-privileged user who can create tables, publications, or subscriptions with crafted names may trigger arbitrary SQL execution when another user opens the affected UI tabs.

Affected context

The vulnerability appears in pgAdmin 4's server-side SQL templates that power the Index Statistics and Publication/Subscription Dependencies views.

It arises specifically when object names (tables, publications, subscriptions) derived from PostgreSQL catalog data are interpolated using raw template variables rather than a quoting routine like qtLiteral.

Deployments where users can create database objects and other users rely on pgAdmin's Statistics or Dependencies tabs to inspect those objects are within the affected context.

Exploit preconditions

  • Attack surface: pgAdmin 4 web interface, specifically the Statistics and Dependencies tabs for:
  • All-indexes statistics listing (coll_stats.sql templates)
  • Publication dependencies and position queries (dependencies.sql, get_position.sql)
  • Subscription dependencies and position queries
  • Required access: Ability for a low-privileged database user to:
  • Connect to the target database
  • CREATE TABLE, CREATE PUBLICATION, or CREATE SUBSCRIPTION
  • Trigger point: A victim (potentially with higher privileges) opens the Statistics or Dependencies tab for a crafted object in pgAdmin, causing pgAdmin to render and execute the associated SQL template.
  • Why exploitation is possible: Object names pulled from pg_catalog are assumed safe and inserted unescaped into SQL templates, allowing an embedded apostrophe to terminate the intended literal and introduce attacker-controlled SQL fragments.

Why this happens

The underlying bug is a classic SQL injection condition caused by unsafe construction of SQL statements from untrusted data.

pgAdmin's Jinja-based templates used {{ name }} directly for identifiers sourced from pg_catalog without passing them through a quoting helper like qtLiteral(conn).

Because PostgreSQL identifiers can contain arbitrary characters when quoted, including apostrophes, this assumption that catalog-derived names are inherently safe breaks down.

This aligns with CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection'), where special characters in user-influenced input are not properly encoded or parameterized before being embedded into SQL.

Potential impact

  • Arbitrary SQL statements may execute in the context of the viewing user's database session.
  • Attackers could alter or delete data accessible to the victim's role.
  • Privilege escalation within the database may occur if the victim has higher privileges than the attacker.
  • Lateral movement to other schemas or databases the victim can access may become possible.
  • Security logging and auditing data may be manipulated or erased.

General mitigation guidance

Effective mitigation centers on ensuring that all dynamic SQL is built using safe, consistent quoting and parameterization patterns.

Common defensive approaches include:

  • Routing all user- or catalog-influenced SQL fragments through a dedicated quoting/escaping routine (e.g., qtLiteral or driver-provided quote functions).
  • Designing templates so that identifiers and values are never concatenated directly, but instead use parameter binding or specialized identifier-quoting APIs.
  • Treating catalog-derived names as untrusted input and applying the same sanitization and encoding rules as for explicit user input.
  • Establishing secure-by-default template helpers where raw interpolation is discouraged or linted, and safe filters are mandatory for SQL fragments.
  • Limiting the privileges of pgAdmin database connections so that even if a query is compromised, its ability to cause damage is constrained.

How teams detect issues like this

Detection typically combines static and review-based techniques:

  • Implement template linting or static analysis that flags raw {{ name }}-style interpolations in SQL templates unless a safe quoting filter is applied.
  • Use automated tests that render each SQL template with intentionally hostile identifiers (e.g., containing apostrophes and stacked statements) and verify the resulting SQL parses as a single statement.
  • Incorporate secure coding checklists into code review, requiring reviewers to verify that all identifiers and values in SQL templates are either parameterized or passed through a quoting helper.
  • Apply policy in CI/CD pipelines that rejects merges when unsafe string concatenation or unfiltered template variables are found in SQL-related code.
  • Consider periodic security-focused review of pgAdmin extensions and plugins, particularly those that introduce new SQL templates.

Sources

SourceLink
github.comgithub.com/pgadmin-org/pgadmin4/commit/73b3218992cc37af6e10b7e54eaeed6ec293c6b2
github.comgithub.com/pgadmin-org/pgadmin4/commit/f75452bfd0f786d0c071638919d48fc1d76f987d
github.comgithub.com/pgadmin-org/pgadmin4/issues/10193

Frequently asked

questions

Yes, in a practical sense. A remote or local attacker with database access can craft specially named objects and then rely on another pgAdmin user to view their Statistics or Dependencies tab, at which point the malicious SQL executes in the viewer's session.

The attacker needs relatively low privileges: the ability to connect to the database and create tables, publications, or subscriptions.

They do not need direct access to pgAdmin itself, only that a pgAdmin user with access to those objects will eventually inspect them.

The safest pattern is to avoid raw string interpolation in SQL and instead:

  • Use parameterized queries for values, and
  • Use dedicated quoting helpers for identifiers, ensuring every template variable that influences SQL passes through those routines.

Establish a development policy where:

  • All SQL construction uses vetted helper APIs or ORMs that handle quoting internally.
  • Template and code linting enforce the use of safe filters or parameters.
  • Security tests routinely inject edge-case identifier names into templates.
  • Code reviewers are trained to treat catalog-derived data as untrusted and to flag any raw interpolation in SQL-related code.
Find out what's already
exploitable in your codebase.