Brief Summary: CVE-2026-23696 — Windmill SQL Injection Enables Full Privilege Escalation and Remote Code Execution

A short review of CVE-2026-23696, a critical SQL injection in Windmill's folder ownership management that allows any authenticated user to escalate to super admin and achieve root remote code execution.

CVE Analysis

8 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-04-07

Brief Summary: CVE-2026-23696 — Windmill SQL Injection Enables Full Privilege Escalation and Remote Code Execution
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A single unsanitized parameter in Windmill's folder ownership API gives any authenticated user, even one confined to the most restricted operator role, a direct path to forging super admin tokens and executing arbitrary code as root. For organizations running Windmill as their workflow backbone or deploying it through Nextcloud Flow, this vulnerability (CVE-2026-23696, CVSS 9.9) represents a complete system compromise achievable in roughly five seconds.

Windmill is an open source workflow engine developed by Windmill Labs, designed to build workflows, data pipelines, and internal tools at scale. It positions itself as an alternative to platforms like Retool and Temporal, offering a developer platform for APIs, background jobs, and user interfaces. The platform is distributed under AGPLv3 for its Community Edition and is also embedded within Nextcloud Flow, extending its reach into the broader Nextcloud ecosystem.

Technical Information

Root Cause: Unsanitized Input in SQL Query Construction

The vulnerability resides in backend/windmill-api/src/folders.rs at lines 698 and 699. The addowner endpoint accepts an owner parameter from a JSON request body and directly interpolates it into a PostgreSQL query using Rust's format! macro. The user supplied value is embedded into a jsonb_set path argument without any sanitization or parameterized query binding. This is a textbook CWE-89 (Improper Neutralization of Special Elements used in an SQL Command) scenario.

Because the input flows directly into the query string rather than through a parameterized query, an attacker can break out of the intended SQL context and inject arbitrary subqueries.

Attack Flow: From Operator to Root in Five Steps

The addowner endpoint requires the caller to be an owner of the target folder. At first glance, this might seem like a meaningful access control barrier. In practice, it is not: any authenticated user can create a new folder, and the creator automatically becomes its owner. This means even the most restricted operator account can satisfy the prerequisite.

The full exploitation chain proceeds as follows:

  1. Folder creation: The operator creates a new folder via the standard API. The platform assigns the operator as the folder's owner automatically.

  2. SQL injection via addowner: The operator sends a crafted payload to the addowner endpoint. The injected SQL contains a subquery that extracts the jwt_secret from the global_settings table. The subquery stores the extracted secret into the folder's extra permissions JSONB column.

  3. Secret retrieval: The operator reads the folder configuration through the normal API, retrieving the JWT signing secret that was written into the JSONB field by the injected subquery.

  4. Evidence cleanup: The operator deletes the folder, removing the forensic artifact from the database. This makes post exploitation detection significantly more difficult.

  5. Token forgery and RCE: Using the leaked JWT secret, the operator forges a new JSON Web Token with super admin privileges. With this token, the operator accesses job execution APIs and achieves root remote code execution.

Scope of Data Exposure

The SQL injection provides unrestricted read access to the entire PostgreSQL database backing the Windmill instance. The following categories of sensitive data are exposed:

Data CategoryImpact
jwt_secretToken forgery leading to immediate RCE
Password hashesOffline password cracking
User emailsAccount enumeration and targeting
API tokensComplete account takeover
Workflow definitionsLeakage of proprietary code and business logic
Resource credentialsLateral movement to connected external systems

The jwt_secret exfiltration is the most consequential vector because it converts a data leak into full system compromise without requiring any additional attack surface.

Patch Analysis

The vendor addressed the vulnerability in commit 942fb62 by introducing a validate_owner function in folders.rs. This function enforces that the owner parameter contains only alphanumeric characters, underscores, hyphens, or slashes. Any input containing characters outside this allowlist causes the API to return a Bad Request error, preventing SQL syntax from reaching the query. A subsequent commit (7a9ef14) applied additional input tightening across the codebase.

Affected Systems and Versions

The following products and version ranges are affected:

  • Windmill Community Edition (CE): versions 1.276.0 through 1.603.2
  • Windmill Enterprise Edition (EE): versions 1.276.0 through 1.603.2
  • Nextcloud Flow: all versions prior to 1.3.0 (which embeds a vulnerable Windmill version)

The patched versions are:

  • Windmill: version 1.603.3 and later
  • Nextcloud Flow: version 1.3.0 and later (which embeds Windmill 1.603.4)

Any deployment of Windmill within the affected version range is vulnerable, regardless of the user role configuration, since even the most restricted operator role can trigger the exploit.

Vendor Security History

The discovery of CVE-2026-23696 occurred alongside several other significant security flaws in the Windmill platform during the same timeframe:

CVETypeSeverityPatched Version
CVE-2026-29059Unauthenticated Path Traversal leading to RCEHigh1.603.3
CVE-2026-23696Authenticated SQL Injection leading to RCECritical1.603.3
CVE-2026-22683Operator Permission BypassHigh1.615.0
CVE-2026-33881NativeTS Code Injection via Environment VariablesN/A1.664.0
CVE-2026-26964Slack OAuth Client Secret ExposureLow1.635.0

This cluster of vulnerabilities highlights the importance of keeping Windmill deployments strictly updated to the latest stable releases. On the positive side, the vendor's response to CVE-2026-23696 was notably fast: the researcher reported the vulnerability on January 11, 2026, and the Windmill founder responded within hours on a Sunday, shipping the patch and awarding a €4,000 bounty the same day. However, Windmill did not assign a CVE identifier for the flaw; VulnCheck stepped in as a CNA to publish CVE-2026-23696.

References

Detect & fix
what others miss

Security magnifying glass visualization