Repository navigation
security: add write_user_memory MCP tool to fix PII cross-user memory leak (#888) - #891
Merged
Merged
Conversation
… leak (#888) Three-layer fix for P0 privacy bug where agents writing to ~/.claude/projects/memory/ during public/channel sessions exposed one user's PII to all subsequent users. Layer 1 — Platform guardrail: PLATFORM_INSTRUCTIONS now explicitly warns agents not to write user-identifying data to the shared memory directory and points them at write_user_memory instead. Layer 2 — write_user_memory MCP tool: Agents call this with their execution_id; the backend resolves the user email server-side from schedule_executions.source_user_email, validating the execution belongs to the calling agent and was triggered by a user-facing channel (public/slack/telegram/whatsapp). The agent never touches email addresses directly. Layer 3 — execution_id in context: ExecutionContext now includes execution_id, rendered as "Execution ID" in the injected system prompt block so agents can pass it to the tool. Files: - services/platform_prompt_service.py: guardrail instruction + execution_id field/render - services/task_execution_service.py: pass execution_id to ExecutionContext - routers/public_memory.py (new): POST /api/agents/{name}/user-memory endpoint - main.py: register new router - mcp-server/src/client.ts: writeUserMemory() method - mcp-server/src/tools/memory.ts (new): write_user_memory tool - mcp-server/src/server.ts + tools/index.ts: register tool Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tool (#888) Add public_memory.py router, POST /api/agents/{name}/user-memory endpoint, and memory.ts MCP tool (17th module) to architecture.md. Update MEM-001 in requirements.md to describe the explicit write path alongside the existing background summarization. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
vybe
added a commit
that referenced
this pull request
Oct 19, 2026
…, Storage, People, one restart banner (ent#887, #888, #890, #891, #353) (#3798) * feat(ui): one Settings home for the agent — rail, General, Guardrails, Storage, People, one restart banner The agent page splits into a working strip and ONE Settings tab, pinned at the end of the strip, with a rail of panes each answering one question (decision on #966). The pane is in the URL (?tab=settings§ion=…); old ?tab=info|guardrails|credentials|folders|access links land on their pane. - General (Abilityai/trinity-enterprise#887): identity (label, id rename, avatar, description, tags), runtime/model/funding, execution timeout (Abilityai/trinity-enterprise#353 — named range error, #929 schedule conflict with an Open Schedules action), parallel capacity, read-only, memory/CPU, template details, Danger zone (reset to main only with a bound repo; delete). The header keeps identity, state, the autonomy chip and the doors; live usage and spend move to Overview; Pull/Push move to the Git tab. - One restart banner: rows report to stores/agentRestart.js; memory/CPU is saved and applied on the next restart instead of restarting at once. - Guardrails (Abilityai/trinity-enterprise#890): rules, self-change permissions (ent#756), gated-skill count, autonomy read-only until PR #2984 merges, cross-model validation, reliability. - Storage (Abilityai/trinity-enterprise#888): repository, GitHub token, git sync, credentials, shared folders, file sharing. Credentials and Folders tabs removed; Sharing loses Distribution. - People (Abilityai/trinity-enterprise#891): the Access tab, unchanged. - Channels/Integrations hold the Voice / MCP cards from the old flat list and point at the tabs that still hold the rest. Red before green: agentSettingsHome.spec.js (7 strip/alias cases) and the file-sharing restart report fail against dev's agentTabs.js and FileSharingPanel.vue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(agent-settings): restore the controls the Settings home dropped, settle the restart banner on the status edge (ent#887, ent#888) A completeness audit against dev found five controls with no new home and three defects in the one restart banner: - Memory/CPU: the "Inherit default" choice is back, so a per-agent override can be cleared again; the editor seeds from the override, not the effective value, and saves an empty choice as null. - Capacity: a stored value above the fleet ceiling says so, and names the value that applies. - Git tab: the "Refresh status" button the header had; the Settings › Storage link is shown only to owners, who have that tab. - General › Avatar: "Next emotion" for a prompt-generated avatar. - Overview: a stopped agent's "Created" line. - The banner's list is cleared on the agent's stopped → running edge, not by the button: a start that fails keeps every waiting change listed (the lifecycle composable reports and returns normally, so the old code read a failed start as success and lost the guardrails / GitHub-token entries), and a manual stop/start from the header settles the list too. - FileSharingPanel resets on an in-place agent switch, so agent A's "restart required" is never announced for agent B. Also: the two @Interactive e2e specs that deep-linked to ?tab=info now open Settings › General → Technical details; user docs name Settings › Storage / People instead of the retired Credentials / Access / Folders tabs. Red first: agentSettingsRestart.mount.spec.js (failed start kept nothing, manual start settled nothing), fileSharingPanelAudience.spec.js (switch carried the wait over), agentSettingsHome.mount.spec.js (no inherit option, no ceiling note) — 5 assertions red on the previous commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(screenshots): drop deleted SettingsPanel.vue from settings-general sources The agent Settings home (ent#887) deletes components/settings/SettingsPanel.vue. That component was the agent page's old Settings tab, never part of the platform Settings view the screenshot shows, and screenshot-guard fails on a missing source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(1712): repoint the ReliabilityPanel wiring guard at the Guardrails pane The agent Settings home (ent#887) deletes components/settings/SettingsPanel.vue and mounts ReliabilityPanel in agent-settings/GuardrailsPane.vue. The guard now reads the pane and asserts the rendered tag, not just the name. Negative control: removing the <ReliabilityPanel> tag turns it red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: trinity-ability <309458136+trinity-ability@users.noreply.github.com>
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
~/.claude/projects/memory/leak that user's PII to every subsequent user of the same agent (the path is shared across all sessions)write_user_memoryMCP tool (isolated store) +execution_idsurfaced in execution context (so the tool can resolve the user server-side)Changes
Layer 1 — Platform guardrail (
platform_prompt_service.py):New "Remembering Things About Users" section in
PLATFORM_INSTRUCTIONSexplicitly prohibits writing user PII to the shared memory directory and explains the correct tool to use instead.Layer 2 —
write_user_memoryMCP tool (newrouters/public_memory.py, newtools/memory.ts):POST /api/agents/{name}/user-memory— agent passesexecution_id; backend resolvessource_user_emailserver-side fromschedule_executions, verifying the execution belongs to this agent and was triggered bypublic/slack/telegram/whatsapp. Agent never touches email addresses.public_user_memorytable (per-(agent_name, user_email)blob, already isolated by MEM-001).Layer 3 —
execution_idin execution context (platform_prompt_service.py,task_execution_service.py):ExecutionContextnow includesexecution_id, rendered as- **Execution ID**: <id>in the injected system prompt block. Agents read this value and pass it towrite_user_memory.Security Properties
user_emailparam accepted)public_user_memorytable was already isolated per(agent_name, user_email)— no schema change neededTest Plan
POST /api/agents/{name}/user-memorywith a valid execution_id from a public chat → returnssuccess: truewith resolved emailwrite_user_memorycallable from an agent-scoped key during a public chat executionExecution IDappears in the injected execution context system prompt blockpublic_user_memoryauto-summarizer (MEM-001) still works — it writes the same column, tool and summarizer coexistFixes #888
🤖 Generated with Claude Code