CVE-2026-26198 Overview
CVE-2026-26198 is a SQL injection vulnerability in Ormar, an async mini ORM for Python developed by collerek. The flaw affects versions 0.9.9 through 0.22.0 and allows unauthenticated attackers to extract arbitrary database contents through the ORM's aggregate query methods. The min() and max() methods in the QuerySet class pass user-supplied column names directly into sqlalchemy.text() without validation. Attackers can inject SQL subqueries as the column parameter to read tables unrelated to the queried model. This vulnerability is tracked under [CWE-89] (SQL Injection) and was patched in version 0.23.0.
Critical Impact
Unauthenticated network attackers can read the entire database contents, including sensitive data in tables outside the queried model, by injecting subqueries into Ormar's aggregate functions.
Affected Products
- Collerek Ormar versions 0.9.9 through 0.22.0
- Python applications using Ormar's QuerySet.min() method with untrusted input
- Python applications using Ormar's QuerySet.max() method with untrusted input
Discovery Timeline
- 2026-02-24 - CVE-2026-26198 published to NVD
- 2026-02-25 - Last updated in NVD database
Technical Details for CVE-2026-26198
Vulnerability Analysis
The vulnerability resides in Ormar's aggregate query construction logic. When an application calls aggregate methods on a QuerySet, the ORM builds SQL expressions by embedding the column parameter directly inside sqlalchemy.text(). This bypasses SQLAlchemy's parameter binding, treating the input as raw SQL.
The sum() and avg() methods include partial protection through an is_numeric type check that rejects fields that do not exist on the model. However, min() and max() skip this validation entirely. An attacker who controls the column argument can inject an arbitrary subquery that the database engine executes within the aggregate function call.
The impact extends beyond the queried model. Because the injected SQL runs with the database connection's privileges, an attacker can query unrelated tables and exfiltrate their contents. The confidentiality impact is high while integrity and availability remain unaffected.
Root Cause
The root cause is missing input validation on column identifiers passed to min() and max() in the QuerySet class. Ormar trusts the caller to supply a legitimate column name and concatenates the string into a raw SQL expression. The fix in version 0.23.0 adds validation consistent with the checks already present on other aggregate methods.
Attack Vector
Exploitation requires network access to any application endpoint that forwards user input to Ormar's min() or max() methods. No authentication or user interaction is required when the vulnerable endpoint is publicly reachable. The attacker supplies a crafted string containing a SQL subquery as the column argument. The database executes the subquery, and its result is returned through the aggregate response. See the GitHub Security Advisory GHSA-xxh2-68g9-8jqr for additional technical detail.
No public proof-of-concept exploit code is available at the time of publication. The vulnerability mechanism is documented in the upstream advisory rather than reproduced here.
Detection Methods for CVE-2026-26198
Indicators of Compromise
- Database query logs containing unexpected subqueries inside MIN( or MAX( function calls
- Application logs showing aggregate API requests with column parameters containing SQL keywords such as SELECT, FROM, or UNION
- Anomalous read access to database tables that the application does not normally query
- Unusually large or slow aggregate query responses originating from public endpoints
Detection Strategies
- Inventory Python applications and identify any dependency on ormar between versions 0.9.9 and 0.22.0 using pip list or lockfile analysis
- Audit application source code for any code path that forwards HTTP request data into the column argument of QuerySet.min() or QuerySet.max()
- Enable verbose SQLAlchemy query logging in staging environments and inspect generated SQL for aggregate expressions containing nested SELECT statements
- Deploy a web application firewall rule that inspects request parameters mapped to aggregate endpoints for SQL metacharacters
Monitoring Recommendations
- Forward database query logs and application access logs to a centralized SIEM and alert on aggregate queries containing nested subqueries
- Monitor for sudden spikes in SELECT activity against sensitive tables that are not part of the application's normal query patterns
- Track outbound response sizes from API endpoints exposing aggregate operations to identify bulk data exfiltration attempts
How to Mitigate CVE-2026-26198
Immediate Actions Required
- Upgrade Ormar to version 0.23.0 or later in all affected Python applications
- Audit application code to remove or refactor any endpoint that passes untrusted input to min() or max() column parameters
- Rotate database credentials and review database audit logs if exploitation is suspected
- Restrict the database user account used by Ormar to the minimum required tables and privileges
Patch Information
The patch is available in Ormar 0.23.0. The fix is published in commit a03bae14fe01358d3eaf7e319fcd5db2e4956b16 and shipped in the 0.23.0 release. The maintainer's security advisory GHSA-xxh2-68g9-8jqr contains the full disclosure details.
Workarounds
- Validate column parameters against an allowlist of known model field names before calling min() or max()
- Avoid exposing aggregate query parameters directly to untrusted callers and use server-side mappings instead
- Apply a least-privilege database role to the Ormar connection so subquery exfiltration is limited to non-sensitive tables
# Upgrade Ormar to the patched release
pip install --upgrade 'ormar>=0.23.0'
# Verify the installed version
pip show ormar | grep -i version
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

