fix(security): scope memory tools to session userId — M2-003/004 #294

Merged
jason.woltje merged 1 commits from fix/m2-prefs-memory-scope into main 2026-03-21 20:19:21 +00:00
Owner

Summary

  • M2-003: Audited packages/memory/src/preferences.ts — all five exported functions (findByUser, findByUserAndKey, findByUserAndCategory, upsert, remove) already correctly filter by userId at the DB WHERE clause level. No gaps found.
  • M2-004: Fixed agent memory tools — removed userId from all four tool parameter schemas (memory_search, memory_save_preference, memory_save_insight, memory_get_preferences) so the LLM cannot inject an arbitrary user ID. The userId is now bound from the authenticated session at tool-creation time via the new sessionUserId parameter on createMemoryTools().
  • Updated buildToolsForSandbox() and the doCreateSession() call site in agent.service.ts to thread the session userId through.

Security Impact

Before this fix, all four memory tools accepted userId as an LLM-controlled parameter, meaning the model could access or write to any user's memory data. The fix closes this injection vector — memory operations are now scoped to the session owner, not to whatever userId the model provides.

Test plan

  • Typecheck: pnpm typecheck — passes
  • Lint: pnpm lint — passes
  • Format: pnpm format:check — passes
## Summary - **M2-003**: Audited packages/memory/src/preferences.ts — all five exported functions (findByUser, findByUserAndKey, findByUserAndCategory, upsert, remove) already correctly filter by userId at the DB WHERE clause level. No gaps found. - **M2-004**: Fixed agent memory tools — removed userId from all four tool parameter schemas (memory_search, memory_save_preference, memory_save_insight, memory_get_preferences) so the LLM cannot inject an arbitrary user ID. The userId is now bound from the authenticated session at tool-creation time via the new sessionUserId parameter on createMemoryTools(). - Updated buildToolsForSandbox() and the doCreateSession() call site in agent.service.ts to thread the session userId through. ## Security Impact Before this fix, all four memory tools accepted userId as an LLM-controlled parameter, meaning the model could access or write to any user's memory data. The fix closes this injection vector — memory operations are now scoped to the session owner, not to whatever userId the model provides. ## Test plan - Typecheck: pnpm typecheck — passes - Lint: pnpm lint — passes - Format: pnpm format:check — passes
jason.woltje added 1 commit 2026-03-21 20:19:02 +00:00
fix(security): scope memory tools to session userId — prevent LLM parameter injection
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
0044481b4c
M2-003: Audited PreferencesRepo — all five functions (findByUser, findByUserAndKey,
findByUserAndCategory, upsert, remove) already enforce userId filtering at the DB
WHERE clause level. No gaps found.

M2-004: Fixed agent memory tools (memory_search, memory_save_preference,
memory_save_insight, memory_get_preferences) — removed userId from all tool
parameter schemas so the LLM cannot inject an arbitrary user ID. The userId is
now bound from the authenticated session at tool-creation time via the new
sessionUserId parameter on createMemoryTools(). buildToolsForSandbox() and the
doCreateSession() call site are updated to thread the session userId through.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jason.woltje merged commit bb22857fde into main 2026-03-21 20:19:21 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#294