Open WebUI, Authorization Bypass, (No CVE) (Medium)

Listen to this Post

How the mentioned CVE works (approximately 20 lines):

The vulnerability exists in `backend/open_webui/models/channels.py` at lines 663–673 within the `is_user_channel_member` function. This function checks for a `ChannelMember` row using `channel_id` and `user_id` but completely ignores the `is_active` field. When a channel owner removes a user (or a user leaves voluntarily), their membership row remains in the database with `is_active=False` and status='left'. Despite this deactivation, `is_user_channel_member` returns `True` because it only verifies row existence. The channel listing API (get_channels_by_user_id) correctly filters on is_active, so the channel disappears from the user’s UI. However, all 15 message-level endpoints in `backend/open_webui/routers/channels.py` rely on `is_user_channel_member` for authorization. An attacker who was previously a member (and knows the channel ID from their membership period) can directly call API endpoints such as `GET /api/v1/channels/{id}/messages` to read new messages, `POST /api/v1/channels/{id}/messages/post` to send messages, `POST /api/v1/channels/{id}/messages/{mid}/update` to edit, and `DELETE /api/v1/channels/{id}/messages/{mid}/delete` to delete messages. The CVSS 3.1 vector is AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N, yielding a base score of 5.4 (Medium). The attack requires a valid user account and prior channel membership, but no user interaction or special conditions. The missing `is_active` check contrasts with the correctly-implemented `get_channel_by_id_and_user_id` method (line 778) which applies ChannelMember.is_active.is_(True). The recommended fix adds `ChannelMember.is_active.is_(True)` to `is_user_channel_member` to align with the rest of the codebase.

dailycve form (3 words max per line):

Platform: Open WebUI
Version: Commit 6fdd19bf1
Vulnerability: Missing is_active check
Severity: Medium 5.4
Date: 2026-05-08

Prediction: Patch within week

What Undercode Say:

Check membership ignoring is_active (vulnerable)
curl -X GET "https://target/api/v1/channels/CHANNEL_ID/messages" \
-H "Authorization: Bearer $TOKEN"
Reproduce: list channels (deactivated channel hidden)
curl -X GET "https://target/api/v1/channels" \
-H "Authorization: Bearer $TOKEN"
Direct read after deactivation
curl -X GET "https://target/api/v1/channels/CHANNEL_ID/messages" \
-H "Authorization: Bearer $TOKEN"
Post message as deactivated user
curl -X POST "https://target/api/v1/channels/CHANNEL_ID/messages/post" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"Still have access"}'
Verify missing filter in code
grep -A5 "def is_user_channel_member" backend/open_webui/models/channels.py

Exploit:

Use known channel ID from previous membership. Send authenticated API requests to message endpoints. No UI indication remains, but all read/write operations succeed.

Protection from this CVE

Apply patch adding `ChannelMember.is_active.is_(True)` to is_user_channel_member. Alternatively, hotfix by overriding the function in a middleware to validate is_active. Regenerate API tokens after removing users and rotate channel IDs.

Impact:

Confidentiality (read new messages), Integrity (post/edit/delete messages), false sense of security, privilege persistence after removal.

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top