Uh oh!
There was an error while loading. Please reload this page.
fix(security): scope search_course_materials by user_id (#125) - #225
Conversation
search_course_materials filtered the documents table on course_id only, but documents are user-scoped within a shared course. It decrypted every enrolled user's summary/concept_notes and fed another student's private content into the requester's tutor/note-chat LLM context. ctx.deps.user_id was available but unused. Thread user_id through as a keyword-only required arg (no silent default that could re-disable scoping) and add user_id to the documents filter; the tool wrapper passes ctx.deps.user_id alongside ctx.deps.course_id. Per-site scoping, consistent with the sibling read_user_progress tool. Test: two docs in one course owned by different users — the scoped query returns only the caller's, and the query carries the caller's user_id filter. Existing call sites updated for the new signature.
Warning Review limit reached
More reviews will be available in 54 minutes and 8 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying with |
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs | frontend | 59b2bac | Commit Preview URL Branch Preview URL | Jun 13 2026, 05:02 AM |
Uh oh!
There was an error while loading. Please reload this page.
Closes#125. P1 / HIGH.
Vulnerability
search_course_materials(agents/tools/chat_context.py) filtered thedocumentstable oncourse_idonly. Documents are user-scoped within a shared course, so the tool returned and decrypted every enrolled user'ssummary/concept_notes, feeding another student's private content into the requester's tutor/note-chat LLM context and answers.ctx.deps.user_idwas available but unused.Fix
Per-site
user_idscoping (consistent with the siblingread_user_progresstool; NOT a change todecrypt_if_present, which stays a context-free field decryptor).user_idis threaded in as a keyword-only, required argument — no default that could silently re-disable the scope — and added to thedocumentsfilter. The tool wrapper passesctx.deps.user_id(the LLM cannot supply it).Negative test (cross-user, fails pre-fix)
TestSearchCourseMaterialsUserScopeintests/test_chat_context_tools.py: two docs in the same course owned by different users, with a faithful row-scoped DB mock. Asserts the caller receives only their own doc, the other user's doc is excluded, and the DB query carriesuser_id=eq.<caller>. On pre-fix code the test can't even express the scoped call (the vulnerable signature has nouser_idparam) → fails; post-fix it demonstrates the leak is closed. Existing call sites + the wrapper test updated for the new signature (the wrapper test now assertsuser_idis pulled from deps).Scope
File-disjoint from #123/#126/#124. Verified the chat-tutor and note-chat agents that register this tool still import cleanly.