Skip to content

🧱 fix: Enforce Agent Access Control on Context and OCR File Loading#12253

Merged
danny-avila merged 9 commits into
devfrom
fix/ocr-resource-access-control
Mar 16, 2026
Merged

🧱 fix: Enforce Agent Access Control on Context and OCR File Loading#12253
danny-avila merged 9 commits into
devfrom
fix/ocr-resource-access-control

Conversation

@danny-avila

@danny-avila danny-avila commented Mar 15, 2026

Copy link
Copy Markdown
Owner

Summary

Fixed an access control gap in primeResources where context and OCR files were fetched from the database by ID without applying the filterFilesByAgentAccess check that already protected the file_search and execute_code paths, allowing any user sharing an agent to receive files they did not own and were not explicitly granted access to via the agent's tool_resources.

  • Added filterFiles as an optional dependency-injected parameter to primeResources, invoked after getFiles on the context/OCR file path to enforce consistent access control across all resource types.
  • Introduced TFilterFilesByAgentAccess exported type in packages/api/src/agents/resources.ts and added filterFilesByAgentAccess?: TFilterFilesByAgentAccess to the InitializeAgentDbMethods interface.
  • Wired filterFilesByAgentAccess from api/server/services/Files/permissions.js into all four agent initialization call sites: primary agent, handoff agents, added-convo agent, and memory agent.
  • Removed the dead fourth options?: { userId?: string; agentId?: string } parameter from TGetFiles, which was defined in the type but never consumed by the underlying File.js implementation.
  • Added isEphemeralAgentId guard to filterFilesByAgentAccess in permissions.js to prevent a fail-closed regression: ephemeral agents have no DB document, causing getAgent to 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.
  • Removed redundant ?. on req.user.role inside the req.user?.id-guarded block in resources.ts.
  • Updated primeResources JSDoc to document the filterFiles and agentId parameters.
  • Corrected import order across client.js, addedConvo.js, and initialize.js to conform to the longest-to-shortest local import convention.
  • Added 5 access control unit tests covering: context file filtering, OCR-merged file filtering, skip-when-no-filterFiles, skip-when-userId-absent, and skip-when-agentId-absent.
  • Strengthened the existing OCR filtering test from toHaveBeenCalled() to toHaveBeenCalledWith(...) with exact argument verification after the OCR→context merge step.
  • Added a test for filterFiles rejection to verify graceful degradation: the outer catch logs the error and restores the original tool_resources.

Change Type

  • Bug fix (non-breaking change which fixes an issue)

Testing

All 36 tests in packages/api/src/agents/resources.test.ts pass, 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 the TFilterFilesByAgentAccess type contract.

To manually verify:

  1. Configure a shared agent with context or OCR file_ids referencing files owned by a different user.
  2. Send a request as the non-owning user — the inaccessible files should be stripped from attachments and not surface in the agent's context window.
  3. Repeat with an ephemeral memory agent to confirm no regression: all files should pass through unfiltered.

Test Configuration:

  • cd packages/api && npx jest resources

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes

…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.
Copilot AI review requested due to automatic review settings March 15, 2026 23:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 TFilterFilesByAgentAccess type and optional filterFiles parameter in primeResources, replacing the previous options parameter on getFiles
  • Wired filterFilesByAgentAccess from permissions.js into 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).
@danny-avila danny-avila changed the title fix/ocr resource access control 🧱 fix: Enforce Agent Access Control on Context and OCR File Loading Mar 16, 2026
…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.
@danny-avila danny-avila merged commit 8e8fb01 into dev Mar 16, 2026
9 checks passed
@danny-avila danny-avila deleted the fix/ocr-resource-access-control branch March 16, 2026 03:02
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants