Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-58225

CVE-2026-58225: Postgrex SQL Injection Vulnerability

CVE-2026-58225 is a SQL injection vulnerability in elixir-ecto Postgrex that allows attackers to inject SQL into notification connections, causing denial of service. This article covers the technical details, affected versions, and mitigation.

Published:

CVE-2026-58225 Overview

CVE-2026-58225 is a SQL injection vulnerability in the Postgrex.Notifications module of the elixir-ecto postgrex PostgreSQL driver [CWE-89]. An attacker who can influence the value passed as a LISTEN channel name can inject content into the reconnect replay query. This breaks the notification connection for every channel sharing it, producing a denial of service. Because quote_channel/1 doubles internal double quotes, arbitrary SQL execution is not possible. The issue affects postgrex from version 0.16.0 before 0.22.3.

Critical Impact

Untrusted input reaching Postgrex.Notifications.listen/3 can silently drop notifications for all tenants sharing the connection, breaking any application logic that depends on PostgreSQL LISTEN/NOTIFY.

Affected Products

  • elixir-ecto postgrex0.16.0 through 0.22.2
  • Elixir/Erlang applications using Postgrex.Notifications.listen/3 with untrusted channel names
  • Downstream libraries embedding postgrex in the affected version range (including ecto_sql deployments)

Discovery Timeline

  • 2026-07-10 - CVE-2026-58225 published to NVD
  • 2026-07-10 - Last updated in NVD database

Technical Details for CVE-2026-58225

Vulnerability Analysis

Postgrex.Notifications sanitizes channel names using quote_channel/1, which doubles embedded double quotes so the name is safe inside a double-quoted identifier. This protects single-statement LISTEN and UNLISTEN paths. However, on every connect and reconnect, handle_connect/1 replays all registered channels at once. It concatenates their LISTEN statements and wraps them in a dollar-quoted anonymous code block of the form DO $$BEGIN ... END$$.

quote_channel/1 does not escape the $$ dollar-quote delimiter that opens and closes this block. The listen/3 guards only reject null bytes and names longer than 63 bytes, so a channel name containing $$ passes validation unchanged. Once embedded, the $$ sequence prematurely terminates the outer dollar-quoted string, and PostgreSQL parses the remainder as additional top-level statements.

Because handle_connect/1 runs on every reconnect, the malformed replay query is rejected each time. The notification connection never re-establishes its subscriptions, silently dropping notifications for every channel sharing that connection.

Root Cause

The root cause is inconsistent quoting between single-statement paths and the batched replay query. quote_channel/1 handles double-quoted identifier escaping but leaves dollar-quote delimiters untouched, allowing the wrapping DO $$...$$ block to be broken by a channel name containing $$.

Attack Vector

An application is affected when it passes untrusted input, such as a tenant or user identifier, as the channel name argument to Postgrex.Notifications.listen/3. Because double-quote doubling prevents forming a fully valid injected statement, arbitrary SQL execution is not possible. The corrupted query reliably breaks the shared notification connection for all tenants, producing denial of service of the LISTEN/NOTIFY subsystem.

text
         |> Map.keys()
         |> Enum.map_join("\n", &~s(LISTEN #{quote_channel(&1)};))
 
-      query = "DO $$BEGIN #{listen_statements} END$$"
+      query = "DO #{dollar_quote("BEGIN #{listen_statements} END")}"
 
       {:query, query, state}
     else

Source: GitHub commit 795c6062. The patch replaces the static $$...$$ wrapper with a dollar_quote/1 helper that selects a delimiter tag not present in the payload.

Detection Methods for CVE-2026-58225

Indicators of Compromise

  • PostgreSQL server logs showing repeated syntax errors on DO $$BEGIN LISTEN ... statements originating from postgrex connection setup.
  • Application logs reporting failed reconnects on Postgrex.Notifications processes accompanied by dropped notification delivery.
  • Channel names in application inputs or database records containing $$ sequences.

Detection Strategies

  • Audit source code for calls to Postgrex.Notifications.listen/3 where the channel argument derives from user, tenant, or request-scoped input.
  • Inspect mix.lock and dependency manifests for postgrex versions between 0.16.0 and 0.22.2 inclusive.
  • Enable PostgreSQL log_min_error_statement = error and alert on DO block syntax errors correlated with client reconnects.

Monitoring Recommendations

  • Track notification delivery latency and consumer-side gaps to detect silent subscription loss after reconnect events.
  • Monitor postgrex client connection lifecycle telemetry for repeated failures on the same notification connection.
  • Alert on any channel name value passed to listen/3 that contains $ characters until dependencies are patched.

How to Mitigate CVE-2026-58225

Immediate Actions Required

  • Upgrade postgrex to version 0.22.3 or later across all applications and services.
  • Inventory every call site of Postgrex.Notifications.listen/3 and confirm whether channel names originate from untrusted input.
  • Until patched, reject or sanitize channel names containing $ characters at the application boundary.

Patch Information

The fix is available in postgrex0.22.3, published in commit 795c6062. The patch replaces the hardcoded $$ dollar-quote delimiter in handle_connect/1 with a dollar_quote/1 helper that chooses a delimiter tag guaranteed not to appear in the wrapped payload. See the GitHub Security Advisory GHSA-4mw9-4qgj-m97w and the OSV record EEF-CVE-2026-58225 for full advisory metadata.

Workarounds

  • Validate channel names against a strict allowlist such as ^[A-Za-z0-9_]{1,63}$ before calling listen/3.
  • Map untrusted identifiers to safe internal channel names using a lookup table or deterministic hash instead of passing raw input.
  • Isolate notification connections per tenant so a corrupted replay query cannot affect notifications for other tenants.
bash
# Update postgrex to the patched release
mix deps.update postgrex
grep '"postgrex"' mix.lock
# Expected: {:hex, :postgrex, "0.22.3", ...}

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.