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

