🧱 fix: Enforce Agent Access Control on Context and OCR File Loading#12253
Merged
Conversation
…oading The context/OCR file path in primeResources fetched files by file_id without applying filterFilesByAgentAccess, unlike the file_search and execute_code paths. Add filterFiles dependency injection to primeResources and invoke it after getFiles to enforce consistent access control.
Pass the filterFilesByAgentAccess function from the JS layer into the TS initializeAgent → primeResources chain via dependency injection, covering primary, handoff, added-convo, and memory agent init paths.
Cover filterFiles invocation with context/OCR files, verify filtering rejects inaccessible files, and confirm graceful fallback when filterFiles, userId, or agentId are absent.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes OCR resource access control by extracting file access filtering from getFiles into a dedicated filterFilesByAgentAccess callback passed to primeResources. This ensures users can only access files they own or have permission to via agent attachment.
Changes:
- Introduced
TFilterFilesByAgentAccesstype and optionalfilterFilesparameter inprimeResources, replacing the previousoptionsparameter ongetFiles - Wired
filterFilesByAgentAccessfrompermissions.jsinto all agent initialization call sites - Added comprehensive test coverage for the new access control filtering logic
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/api/src/agents/resources.ts | Added TFilterFilesByAgentAccess type, filterFiles param, and post-query filtering logic |
| packages/api/src/agents/resources.test.ts | Added tests for access control filtering including edge cases |
| packages/api/src/agents/initialize.ts | Updated InitializeAgentDbMethods interface and passed filterFiles to primeResources |
| api/server/services/Endpoints/agents/initialize.js | Wired filterFilesByAgentAccess into both initializeAgent calls |
| api/server/services/Endpoints/agents/addedConvo.js | Wired filterFilesByAgentAccess into added convo agent init |
| api/server/controllers/agents/client.js | Wired filterFilesByAgentAccess into AgentClient init |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
Ephemeral agents have no DB document, so getAgent returns null and the access map defaults to all-false, silently blocking all non-owned files. Short-circuit with isEphemeralAgentId to preserve the pass-through behavior for inline-built agents (memory, tool agents).
Remove redundant optional chain on req.user.role inside user-guarded block, update primeResources JSDoc with filterFiles and agentId params, and reorder JS imports to longest-to-shortest per project conventions.
Use toHaveBeenCalledWith for the OCR filtering test to verify exact arguments after the OCR→context merge step. Add test for filterFiles rejection to verify graceful degradation (logs error, returns original tool_resources).
Sort by total line length descending: loadAddedAgent (91) before filterFilesByAgentAccess (84), loadAgentTools (91) before filterFilesByAgentAccess (84).
…sViaAgent Cover every branch in permissions.js: ephemeral agent guard, missing userId/agentId/files early returns, all-owned short-circuit, mixed owned + non-owned with VIEW/no-VIEW, agent-not-found fail-closed, author path scoped to attached files, EDIT gate on delete, DB error fail-closed, and agent with no tool_resources.
Files with no user field fall into the non-owned path and get run through hasAccessToFilesViaAgent. Add two cases: attached file with no user field is returned, unattached file with no user field is excluded.
jcbartle
pushed a commit
to jcbartle/LibreChat
that referenced
this pull request
May 11, 2026
…anny-avila#12253) * 🔏 fix: Apply agent access control filtering to context/OCR resource loading The context/OCR file path in primeResources fetched files by file_id without applying filterFilesByAgentAccess, unlike the file_search and execute_code paths. Add filterFiles dependency injection to primeResources and invoke it after getFiles to enforce consistent access control. * fix: Wire filterFilesByAgentAccess into all agent initialization callers Pass the filterFilesByAgentAccess function from the JS layer into the TS initializeAgent → primeResources chain via dependency injection, covering primary, handoff, added-convo, and memory agent init paths. * test: Add access control filtering tests for primeResources Cover filterFiles invocation with context/OCR files, verify filtering rejects inaccessible files, and confirm graceful fallback when filterFiles, userId, or agentId are absent. * fix: Guard filterFilesByAgentAccess against ephemeral agent IDs Ephemeral agents have no DB document, so getAgent returns null and the access map defaults to all-false, silently blocking all non-owned files. Short-circuit with isEphemeralAgentId to preserve the pass-through behavior for inline-built agents (memory, tool agents). * fix: Clean up resources.ts and JS caller import order Remove redundant optional chain on req.user.role inside user-guarded block, update primeResources JSDoc with filterFiles and agentId params, and reorder JS imports to longest-to-shortest per project conventions. * test: Strengthen OCR assertion and add filterFiles error-path test Use toHaveBeenCalledWith for the OCR filtering test to verify exact arguments after the OCR→context merge step. Add test for filterFiles rejection to verify graceful degradation (logs error, returns original tool_resources). * fix: Correct import order in addedConvo.js and initialize.js Sort by total line length descending: loadAddedAgent (91) before filterFilesByAgentAccess (84), loadAgentTools (91) before filterFilesByAgentAccess (84). * test: Add unit tests for filterFilesByAgentAccess and hasAccessToFilesViaAgent Cover every branch in permissions.js: ephemeral agent guard, missing userId/agentId/files early returns, all-owned short-circuit, mixed owned + non-owned with VIEW/no-VIEW, agent-not-found fail-closed, author path scoped to attached files, EDIT gate on delete, DB error fail-closed, and agent with no tool_resources. * test: Cover file.user undefined/null in permissions spec Files with no user field fall into the non-owned path and get run through hasAccessToFilesViaAgent. Add two cases: attached file with no user field is returned, unattached file with no user field is excluded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixed an access control gap in
primeResourceswhere context and OCR files were fetched from the database by ID without applying thefilterFilesByAgentAccesscheck that already protected thefile_searchandexecute_codepaths, allowing any user sharing an agent to receive files they did not own and were not explicitly granted access to via the agent'stool_resources.filterFilesas an optional dependency-injected parameter toprimeResources, invoked aftergetFileson the context/OCR file path to enforce consistent access control across all resource types.TFilterFilesByAgentAccessexported type inpackages/api/src/agents/resources.tsand addedfilterFilesByAgentAccess?: TFilterFilesByAgentAccessto theInitializeAgentDbMethodsinterface.filterFilesByAgentAccessfromapi/server/services/Files/permissions.jsinto all four agent initialization call sites: primary agent, handoff agents, added-convo agent, and memory agent.options?: { userId?: string; agentId?: string }parameter fromTGetFiles, which was defined in the type but never consumed by the underlyingFile.jsimplementation.isEphemeralAgentIdguard tofilterFilesByAgentAccessinpermissions.jsto prevent a fail-closed regression: ephemeral agents have no DB document, causinggetAgentto return null and the access map to default all-false, silently stripping non-owned files for inline-built agents such as memory and tool agents.?.onreq.user.roleinside thereq.user?.id-guarded block inresources.ts.primeResourcesJSDoc to document thefilterFilesandagentIdparameters.client.js,addedConvo.js, andinitialize.jsto conform to the longest-to-shortest local import convention.toHaveBeenCalled()totoHaveBeenCalledWith(...)with exact argument verification after the OCR→context merge step.filterFilesrejection to verify graceful degradation: the outer catch logs the error and restores the originaltool_resources.Change Type
Testing
All 36 tests in
packages/api/src/agents/resources.test.tspass, including the 7 new and modified access control tests. The new tests exercise the full filtering lifecycle without real DB access via Jest mocks conforming to theTFilterFilesByAgentAccesstype contract.To manually verify:
file_idsreferencing files owned by a different user.attachmentsand not surface in the agent's context window.Test Configuration:
cd packages/api && npx jest resourcesChecklist