PYSEC-2026-3604
Vulnerability from pysec - Published: 2026-08-04 11:34 - Updated: 2026-08-04 13:36Summary
POST /api/v1/images/edit performed no authorization beyond requiring a verified account. Every other image-editing surface in Open WebUI enforces the global image-edit switch and the per-user image-generation permission — the /api/v1/images/generations route, the built-in edit_image tool, and the chat image-edit middleware — but the direct edit route enforced neither. A verified non-admin user could therefore invoke server-side image editing, reaching the configured image-edit provider with the administrator's credentials, even when the administrator had globally disabled image editing (ENABLE_IMAGE_EDIT=False) or denied that user image-generation permission. The image-editing UI is surfaced only to administrators (Playground), so the route additionally exposed an admin-only capability to any verified user.
Impact
An authenticated, non-admin user can:
- bypass the global
ENABLE_IMAGE_EDIT=Falseadministrator control; - bypass a denied per-user/group
features.image_generationpermission; - cause the server to send billable image-edit requests to the configured provider (OpenAI-compatible, Gemini, or ComfyUI) using administrator-configured credentials (
IMAGES_EDIT_OPENAI_API_KEYfor the OpenAI engine).
No cross-user data is exposed and the provider credentials are never returned to the caller; the impact is the control/permission bypass and the associated billable resource consumption.
Affected Versions
>= 0.8.11, < 0.10.0 (the /api/v1/images/edit route was introduced in 0.8.11 and was ungated from the outset). Fixed in v0.10.0.
Details
/api/v1/images/generations enforces ENABLE_IMAGE_GENERATION (403 if globally disabled) and features.image_generation (403 for non-admins without the permission). The edit_image built-in tool and the chat image-edit middleware likewise gate on ENABLE_IMAGE_EDIT and features.image_generation. The direct POST /api/v1/images/edit route ran on Depends(get_verified_user) alone and proceeded straight to provider dispatch, applying none of these controls.
Proof of Concept
As a verified non-admin user, with image editing globally disabled (ENABLE_IMAGE_EDIT=False) or features.image_generation denied for the user:
POST /api/v1/images/edit
Authorization: Bearer <non_admin_user_token>
Content-Type: application/json
{"image":"data:image/png;base64,<png>","prompt":"edit","model":"gpt-image-1"}
The request reaches the configured image-edit provider and returns an edited image despite the disabled control/permission.
Patch
The direct route is split from its shared implementation (mirroring generate_images/image_generations): a thin /edit route now enforces ENABLE_IMAGE_EDIT and the per-user features.image_generation permission before delegating to the shared image_edits() implementation. The internal callers (the edit_image tool and the chat middleware) call the implementation directly and already gate themselves, so they are unaffected.
| Name | purl | open-webui | pkg:pypi/open-webui |
|---|
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "open-webui",
"purl": "pkg:pypi/open-webui"
},
"ranges": [
{
"events": [
{
"introduced": "0.8.11"
},
{
"fixed": "0.10.0"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"0.8.11",
"0.8.12",
"0.9.0",
"0.9.1",
"0.9.2",
"0.9.3",
"0.9.4",
"0.9.5",
"0.9.6"
]
}
],
"aliases": [
"CVE-2026-59227",
"GHSA-rqj7-6wrp-6g2g"
],
"details": "## Summary\n\n`POST /api/v1/images/edit` performed no authorization beyond requiring a verified account. Every other image-editing surface in Open WebUI enforces the global image-edit switch and the per-user image-generation permission \u2014 the `/api/v1/images/generations` route, the built-in `edit_image` tool, and the chat image-edit middleware \u2014 but the direct edit route enforced neither. A verified non-admin user could therefore invoke server-side image editing, reaching the configured image-edit provider with the administrator\u0027s credentials, even when the administrator had globally disabled image editing (`ENABLE_IMAGE_EDIT=False`) or denied that user image-generation permission. The image-editing UI is surfaced only to administrators (Playground), so the route additionally exposed an admin-only capability to any verified user.\n\n## Impact\n\nAn authenticated, non-admin user can:\n\n- bypass the global `ENABLE_IMAGE_EDIT=False` administrator control;\n- bypass a denied per-user/group `features.image_generation` permission;\n- cause the server to send billable image-edit requests to the configured provider (OpenAI-compatible, Gemini, or ComfyUI) using administrator-configured credentials (`IMAGES_EDIT_OPENAI_API_KEY` for the OpenAI engine).\n\nNo cross-user data is exposed and the provider credentials are never returned to the caller; the impact is the control/permission bypass and the associated billable resource consumption.\n\n## Affected Versions\n\n`\u003e= 0.8.11, \u003c 0.10.0` (the `/api/v1/images/edit` route was introduced in 0.8.11 and was ungated from the outset). Fixed in **v0.10.0**.\n\n## Details\n\n`/api/v1/images/generations` enforces `ENABLE_IMAGE_GENERATION` (403 if globally disabled) and `features.image_generation` (403 for non-admins without the permission). The `edit_image` built-in tool and the chat image-edit middleware likewise gate on `ENABLE_IMAGE_EDIT` and `features.image_generation`. The direct `POST /api/v1/images/edit` route ran on `Depends(get_verified_user)` alone and proceeded straight to provider dispatch, applying none of these controls.\n\n## Proof of Concept\n\nAs a verified non-admin user, with image editing globally disabled (`ENABLE_IMAGE_EDIT=False`) or `features.image_generation` denied for the user:\n\n```http\nPOST /api/v1/images/edit\nAuthorization: Bearer \u003cnon_admin_user_token\u003e\nContent-Type: application/json\n\n{\"image\":\"data:image/png;base64,\u003cpng\u003e\",\"prompt\":\"edit\",\"model\":\"gpt-image-1\"}\n```\n\nThe request reaches the configured image-edit provider and returns an edited image despite the disabled control/permission.\n\n## Patch\n\nThe direct route is split from its shared implementation (mirroring `generate_images`/`image_generations`): a thin `/edit` route now enforces `ENABLE_IMAGE_EDIT` and the per-user `features.image_generation` permission before delegating to the shared `image_edits()` implementation. The internal callers (the `edit_image` tool and the chat middleware) call the implementation directly and already gate themselves, so they are unaffected.",
"id": "PYSEC-2026-3604",
"modified": "2026-08-04T13:36:26.995054Z",
"published": "2026-08-04T11:34:42.578333Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/open-webui/open-webui/security/advisories/GHSA-rqj7-6wrp-6g2g"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59227"
},
{
"type": "WEB",
"url": "https://github.com/open-webui/open-webui/pull/26009"
},
{
"type": "WEB",
"url": "https://github.com/open-webui/open-webui/commit/e038bab66dec8d17212eec35b5cb6d6b785a4200"
},
{
"type": "PACKAGE",
"url": "https://github.com/open-webui/open-webui"
},
{
"type": "WEB",
"url": "https://github.com/open-webui/open-webui/releases/tag/v0.10.0"
},
{
"type": "PACKAGE",
"url": "https://pypi.org/project/open-webui"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-rqj7-6wrp-6g2g"
}
],
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "Open WebUI: POST /api/v1/images/edit bypasses the global image-edit switch and the per-user image-generation permission"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.