CVE-2026-32687 Overview
CVE-2026-32687 is a SQL injection vulnerability in the Elixir.Postgrex.Notifications module of the elixir-ecto postgrex PostgreSQL driver. The flaw allows attackers who control channel names to inject arbitrary SQL through listen/3 and unlisten/3 calls. Channel arguments are interpolated directly into LISTEN "..." and UNLISTEN "..." statements without escaping the " character. Because the notifications connection uses the PostgreSQL simple query protocol, multi-statement payloads execute, enabling chained DDL and DML commands such as ; DROP TABLE ...; --. The vulnerability affects postgrex versions from 0.16.0 before 0.22.2 and is tracked under [CWE-89].
Critical Impact
An attacker who influences a Postgrex channel name can execute arbitrary SQL — including destructive DROP, INSERT, UPDATE, and DELETE statements — against the backing PostgreSQL database.
Affected Products
- elixir-ecto postgrex from version 0.16.0 before 0.22.2
- Elixir applications calling Elixir.Postgrex.Notifications.listen/3 with attacker-influenced channel names
- Elixir applications calling Elixir.Postgrex.Notifications.unlisten/3 with attacker-influenced channel names
Discovery Timeline
- 2026-05-12 - CVE-2026-32687 published to NVD
- 2026-05-13 - Last updated in NVD database
Technical Details for CVE-2026-32687
Vulnerability Analysis
The vulnerability resides in lib/postgrex/notifications.ex within the routines Elixir.Postgrex.Notifications.listen/3, Elixir.Postgrex.Notifications.unlisten/3, and Elixir.Postgrex.Notifications.handle_connect/1. These routines build SQL statements by concatenating the channel argument inside double-quoted identifiers without sanitizing embedded " characters.
PostgreSQL treats " as the quoted identifier delimiter. By injecting a single ", an attacker terminates the identifier and appends additional SQL. The notifications connection uses the PostgreSQL simple query protocol, which permits multiple semicolon-separated statements in one request. This converts a single-identifier injection into a full multi-statement SQL execution primitive.
The same unsanitized interpolation runs again in handle_connect/1, which replays previously registered LISTEN commands after a reconnect. Persistent attacker-controlled channel names therefore re-trigger execution on every reconnection event.
Root Cause
The root cause is improper neutralization of special elements in a SQL command [CWE-89]. The channel parameter is treated as a trusted identifier and embedded directly into the query string without escaping the identifier delimiter ".
Attack Vector
Exploitation requires that an attacker influence the value passed as the channel argument. Applications that derive channel names from user input, HTTP parameters, message payloads, or other external sources are exposed. A payload such as legit"; DROP TABLE users; -- breaks out of the quoted identifier and chains arbitrary statements through the simple query protocol.
The vulnerability mechanism is described in prose only — no verified public exploit code is referenced. See the CNA CVE-2026-32687 Advisory and the GitHub Security Advisory GHSA-r73h-97w8-m54h for the upstream technical write-up.
Detection Methods for CVE-2026-32687
Indicators of Compromise
- PostgreSQL server logs containing LISTEN or UNLISTEN statements with unexpected " characters, semicolons, or trailing SQL keywords such as DROP, INSERT, UPDATE, or CREATE.
- Unexpected DDL or DML executions originating from the database role used by the Postgrex notifications connection.
- Repeated execution of the same suspicious LISTEN payload after application restarts, indicating replay through handle_connect/1.
Detection Strategies
- Enable PostgreSQL log_statement = 'all' on non-production environments and audit LISTEN/UNLISTEN traffic for embedded quote characters.
- Perform static analysis of Elixir codebases to locate every call site of Postgrex.Notifications.listen/3 and unlisten/3, flagging any where the channel argument is not a hard-coded literal.
- Compare deployed postgrex versions against the fixed release 0.22.2 using dependency inventory tooling (mix deps, SBOM scanners).
Monitoring Recommendations
- Alert on PostgreSQL audit events where the executing role matches the Postgrex notifications connection but the statement type is DDL or destructive DML.
- Monitor application logs for runtime channel names that contain non-identifier characters such as ", ;, or whitespace.
How to Mitigate CVE-2026-32687
Immediate Actions Required
- Upgrade postgrex to version 0.22.2 or later in all Elixir applications.
- Audit every call to Postgrex.Notifications.listen/3 and unlisten/3 and remove any path where channel names derive from untrusted input.
- Restrict the PostgreSQL role used by Postgrex notifications connections to the minimum privileges required, removing DDL and broad DML rights.
Patch Information
The maintainers fixed the issue in postgrex0.22.2. The patch escapes the " character in channel identifiers before interpolating them into LISTEN/UNLISTEN statements and applies the same handling to the reconnect replay path in handle_connect/1. See the GitHub Commit for Postgrex and the OSV Vulnerability EEF-CVE-2026-32687 record for fix metadata.
Workarounds
- If immediate upgrade is not possible, validate channel names against a strict allowlist (for example, ^[A-Za-z0-9_]+$) before passing them to listen/3 or unlisten/3.
- Hard-code channel names as compile-time literals rather than deriving them from runtime input.
- Apply least-privilege at the database layer so the notifications role cannot execute destructive statements even if injection succeeds.
# Update postgrex in mix.exs and refresh the lockfile
# {:postgrex, "~> 0.22.2"}
mix deps.update postgrex
mix deps.get
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


