Improve security: prevent object enumeration and unify permission checks#1024
Improve security: prevent object enumeration and unify permission checks#1024
Conversation
Replace direct .objects.get() with .objects.visible_to_user() in four mutations (UpdateDocumentSummary, StartDocumentAnalysisMutation, RestoreDeletedDocument, PermanentlyDeleteDocument) to prevent object-existence enumeration by unauthorized users. Also unify error messages across all failure paths so that "not found" and "no permission" return the same response, and replace ad-hoc creator/is_public checks with guardian-based permission checks (user_has_permission_for_obj / visible_to_user) for consistency with the rest of the codebase. https://claude.ai/code/session_01Qgk1iTRL4mFWpYRhouXWo4
Code ReviewThe direction of this PR is correct — using 🚨 Potential Breaking Change:
|
| # | Severity | Location | Issue |
|---|---|---|---|
| 1 | High | UpdateDocumentSummary permission check |
Corpus creator without guardian perms (direct-created) now denied; test may fail |
| 2 | Medium | UpdateDocumentSummary exception handler |
Inner exception message still leaked to client |
| 3 | Low | RestoreDeletedDocument |
Generic error where a specific, non-leaking message is correct |
| 4 | Low | Both restore/delete mutations | Service error strings still forwarded to client (pre-existing) |
| 5 | Low | Test coverage | No test for the anti-enumeration property being added |
…utation-security-aRiy7
- Fix UpdateDocumentSummary permission: also allow corpus creator (not just explicit guardian perms) to create summaries - Fix UpdateDocumentSummary exception handler: log error details server-side instead of leaking str(e) to client - Fix RestoreDeletedDocument: use specific non-leaking message when document is not in deleted state (was incorrectly using generic "not found" message for a legitimate state check) - Update test assertion to match new error message - Merge latest main
Code ReviewA previous automated review left several findings that need correction, plus a couple of genuine issues. Ordered by severity. Correction: previous Finding 2 was incorrectThe prior review claimed Correction: previous Finding 3 was incorrectThe prior review claimed [Medium] Undocumented behavioral change: public-corpus summary creationThe previous review flagged a creator-check regression but got the specifics wrong. Here is the accurate picture. Old permission logic when creating a new summary (no New permission logic ( has_perm = corpus.creator == user or user_has_permission_for_obj(
user_val=user, instance=corpus, permission=PermissionTypes.UPDATE,
include_group_permissions=True,
)The creator check is preserved (the prior review was wrong). The This is arguably the correct security posture (visibility ≠ write access), but it is a breaking behavioral change not documented in the PR description. Please call it out explicitly so operators upgrading are aware. Test impact: the existing [Low]
|
| Severity | Location | Issue |
|---|---|---|
| Medium | UpdateDocumentSummary |
is_public corpus write access silently removed; undocumented breaking change |
| Low | StartDocumentAnalysisMutation L168 |
Outer catch still leaks str(e) to client |
| Low | RestoreDeletedDocument, PermanentlyDeleteDocument |
Service error strings still forwarded (pre-existing) |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Summary
This PR enhances security by preventing object-existence enumeration attacks and unifying permission checks across GraphQL mutations. The changes ensure that users cannot determine whether a resource exists based on error messages, and that permission checks consistently use the application's permission system.
Key Changes
Prevent object-existence enumeration: Modified three mutations (
UpdateDocumentSummary,RestoreDeletedDocument,PermanentlyDeleteDocument) to usevisible_to_user()querysets instead of direct.get()calls. This prevents attackers from determining if a document or corpus exists by observing different error messages.Unified error messages: Replaced specific error messages ("Document not found", "Corpus not found", "You can only edit summaries you created") with a generic message: "Document or corpus not found, or you do not have permission." This prevents information leakage about resource existence.
Consistent permission checking: Updated
StartDocumentAnalysisMutationto usevisible_to_user()querysets instead of checkingis_publicandcreatorfields directly, ensuring consistent permission enforcement across the codebase.Improved permission logic: In
UpdateDocumentSummary, replaced manual permission checks with theuser_has_permission_for_obj()utility function with proper guardian integration for corpus update permissions.Cleaner exception handling: Removed redundant
DoesNotExistexception handlers since objects are now retrieved through filtered querysets that return early if not found.Better error messages: Simplified generic error messages in exception handlers to avoid exposing implementation details.
Implementation Details
visible_to_user()to filter querysets before retrieval, ensuring permission checks happen at the database levelCorpusimport was moved to the top ofanalysis_mutations.pyfor consistencyuser_has_permission_for_obj()utility function where applicablehttps://claude.ai/code/session_01Qgk1iTRL4mFWpYRhouXWo4