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:
-
Folder creation: The operator creates a new folder via the standard API. The platform assigns the operator as the folder's owner automatically.
-
SQL injection via addowner: The operator sends a crafted payload to the
addownerendpoint. The injected SQL contains a subquery that extracts thejwt_secretfrom theglobal_settingstable. The subquery stores the extracted secret into the folder's extra permissions JSONB column. -
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.
-
Evidence cleanup: The operator deletes the folder, removing the forensic artifact from the database. This makes post exploitation detection significantly more difficult.
-
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 Category | Impact |
|---|---|
jwt_secret | Token forgery leading to immediate RCE |
| Password hashes | Offline password cracking |
| User emails | Account enumeration and targeting |
| API tokens | Complete account takeover |
| Workflow definitions | Leakage of proprietary code and business logic |
| Resource credentials | Lateral 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:
| CVE | Type | Severity | Patched Version |
|---|---|---|---|
| CVE-2026-29059 | Unauthenticated Path Traversal leading to RCE | High | 1.603.3 |
| CVE-2026-23696 | Authenticated SQL Injection leading to RCE | Critical | 1.603.3 |
| CVE-2026-22683 | Operator Permission Bypass | High | 1.615.0 |
| CVE-2026-33881 | NativeTS Code Injection via Environment Variables | N/A | 1.664.0 |
| CVE-2026-26964 | Slack OAuth Client Secret Exposure | Low | 1.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
- NVD Entry for CVE-2026-23696
- VulnCheck Advisory: Windmill File Ownership Handling SQLi RCE
- Chocapikk: Windfall — From Path Traversal to RCE in Nextcloud Flow and Windmill
- GitHub: Chocapikk/Windfall Exploit Toolkit
- Windmill Patch Commit 942fb62
- Windmill Patch Commit 7a9ef14 (Additional Input Tightening)
- Windmill Release v1.603.3
- Nextcloud Flow Patch Commit b9f5d86
- Nextcloud Flow App Releases
- Windmill Official Website
- Windmill GitHub Repository
- OpenCVE: Windmill CVEs and Security Vulnerabilities



