GHSA-p4fx-23fq-jfg6 Open WebUI: Missing `workspace.tools` Authorization Check on Tool Update Endpoint Allows Privilege Escalation to Code Execution
SummaryThe tool update endpoint (`POST /api/v1/tools/id/{id}/update`) is missing the `workspace.tools` permission check that is present on the tool create endpoint. This allows a user who has been explicitly **denied** tool management capabilities ( and who the administrator considers **untrusted** for code execution )  to replace a tool's server-side Python content and trigger execution, bypassing the intended `workspace.tools` security boundary.Open WebUI's security policy correctly states that `workspace.tools` is the trust boundary for code execution: *"Granting a user the ability to create Tools is equivalent to giving them shell access to the server."* This vulnerability breaks that boundary. A `write` access grant on a single tool is sufficient to bypass `workspace.tools` entirely.This is **not** a report about exec() being unsandboxed (that is acknowledged as intended behavior). This is a report about a **missing authorization check** that allows an untrusted user to reach the exec() sink that should be gated behind `workspace.tools`.Root CauseThe create and update endpoints for tools have **asymmetric authorization checks**. The create endpoint enforces the `workspace.tools` permission; the update endpoint does not.Create endpoint, enforces `workspace.tools`**File**: `backend/open_webui/routers/tools.py`, lines 326-345Update endpoint  does NOT enforce `workspace.tools`**File**: `backend/open_webui/routers/tools.py`, lines 451-485The `write` access grant is a collaboration primitive used across the application (knowledge bases, prompts, models, tools) for content editing. On every other resource type, a `write` grant allows editing metadata and content. On tools specifically, because the update endpoint triggers `exec()`, a `write` grant silently escalates to code execution but **only because the `workspace.tools` check is missing**. If the check were present (as it is on create), the `write` grant would not confer execution privilege.Prerequisites**Attacker (Bob)**: A regular user account with **no** `workspace.tools` permission. `workspace.tools` is disabled by default (`config.py:1364-1366`), so this is the **default state** for all non-admin users.**Collaborator (Alice)**: A user with `workspace.tools` permission who creates a tool and grants `write` access to Bob. This is a normal collaboration workflow  Alice is sharing editing access, not granting code execution rights.No admin action required beyond the initial `workspace.tools` grant to Alice (which is the intended, documented workflow).**Note on default configuration**: The `workspace.tools` permission defaults to `false`. An administrator must explicitly enable it for at least one user (Alice). This is a **documented, recommended workflow**  the security policy explicitly describes granting `workspace.tools` to trusted users. The vulnerability is not that Alice has this permission; it is that Bob can bypass it.Proof of ConceptEnvironmentDefault configuration. Admin creates an account, enables `workspace.tools` for trusted users via Admin Panel > Settings > User Permissions.Step-by-step reproduction**Step 1  Setup users**Create two non-admin users: Alice (trusted, will get `workspace.tools`) and Bob (untrusted, will NOT get `workspace.tools`).**Step 2  Admin enables `workspace.tools` globally**This is the documented workflow for allowing trusted users to build tools.**Step 3  Alice creates a benign tool****Step 4  Alice grants write access to Bob (collaboration)**Alice wants Bob to be able to edit the tool's description or parameters. This is a standard collaboration feature.**Step 5  Admin disables `workspace.tools`**Admin revokes the global permission. Now neither Alice nor Bob (nor any non-admin) should be able to execute code via tools.**Step 6  Verify Bob CANNOT create tools****Step 7  Bob updates the tool content → code execution (the bypass)**Bob replaces the tool's Python content. The update endpoint does not check `workspace.tools`, only the `write` access grant. The new content is passed to `exec()`.Actual PoC OutputThe following is a complete run of the automated PoC script:Burp Collaborator EvidenceThe container made an outbound HTTP POST to a Collaborator server, confirming code execution from within the container:Security Boundary ViolatedOpen WebUI's security policy defines `workspace.tools` as the trust boundary for code execution:*"Tool creation is controlled by the workspace.tools permission, which is disabled by default for non-admin users and should only be granted to fully trusted users who are equivalent to system administrators in terms of trust. Granting a user the ability to create Tools is equivalent to giving them shell access to the server."*This vulnerability breaks that boundary:| Check | Create endpoint (line 333) | Update endpoint (line 467) |
|-------|---------------------------|---------------------------|
| `user.role == 'admin'` | Yes | Yes |
| `has_permission('workspace.tools')` | **Yes** | **No** |
| `has_permission('workspace.tools_import')` | **Yes** | **No** |
| `AccessGrants.has_access('write')` | No | Yes |
| `tools.user_id == user.id` | No (new tool) | Yes |The update endpoint substitutes `AccessGrants.has_access('write')` where `has_permission('workspace.tools')` should be. A `write` grant is a collaboration primitive for editing content; `workspace.tools` is the code execution trust boundary. These are different privilege levels, but the update endpoint conflates them.ImpactAn attacker with a regular user account and a `write` access grant on any single tool can:Execute arbitrary server-side code as root (PID 1 in the default Docker deployment)Read sensitive environment variables (`WEBUI_SECRET_KEY`, `OPENAI_API_KEY`, etc.)Read/write the application database (all users' chats, files, API keys)Read arbitrary files from the container filesystemMake outbound network requests to internal servicesThe attacker **never** needs `workspace.tools` permission. The administrator's explicit decision to deny this user code execution capability is bypassed.RemediationRecommended FixAdd the `workspace.tools` permission check to the update endpoint, matching the create endpoint's authorization gate:**File**: `backend/open_webui/routers/tools.py`, after line 481 (after the existing access check)This allows users with `write` grants to update tool metadata (name, description, valves) without `workspace.tools`, but requires the permission for content changes that trigger code execution.
CVSS v3.1 score: 7.2