Submit #844651: DeepMyst Mysti 0.4.0 Information Exposure / Improper Isolationinfo

TitleDeepMyst Mysti 0.4.0 Information Exposure / Improper Isolation
Description## Vulnerability Title Cross-Tenant Data Exposure via Hash-Key Confusion in Project Auto-Memory ## Affected Component `src/managers/MemoryManager.ts` Repository: https://github.com/DeepMyst/Mysti ## Summary An attacker with the ability to reuse or influence a shared lexical workspace path in a shared `$HOME` environment can craft two non-equivalent workspace identities that produce the same project-memory key. This causes memory-key reuse, leading to another real project's `MEMORY.md` being loaded into the attacker's agent context, exposing sensitive cross-tenant data. ## Technical Details The vulnerability occurs because `MemoryManager` computes a project-memory key over the literal `workspacePath` string and uses the resulting truncated digest as the filesystem namespace for persisted agent memory. The digest does not include critical security-relevant fields needed to identify the real workspace or trust domain. **Where the Hash is Computed** In `src/managers/MemoryManager.ts`, the hash is derived solely from the lexical path of the workspace and truncated to 12 characters: ```ts initProjectMemory(workspacePath: string): void { const hash = crypto.createHash('sha256').update(workspacePath).digest('hex').substring(0, 12); const homeDir = process.env.HOME || process.env.USERPROFILE || ''; this._projectMemoryDir = path.join(homeDir, '.mysti', 'projects', hash, 'memory'); // ... ``` The workspace path comes directly from VS Code's first workspace folder (`vscode.workspace.workspaceFolders[0].uri.fsPath`). **Why Hash Equality Does Not Imply Security Equivalence** The digest completely excludes the canonical real workspace path, symlink/bind-mount target identities, application-level `user_id`, or tenant identity. For example, `/work/current` may be a symlink. At one time it may resolve to Alice's private project, and later to Bob's project. Both sessions hash the exact same literal string (`/work/current`) and reuse the exact same memory namespace (`~/.mysti/projects/<hash>/memory`), even though the real workspaces and users are completely different. **How the Attacker Constructs a Conflicting Object** Victim workspace object: ```json { "workspacePath": "/work/current", "canonical_workspace_path": "/srv/users/alice/payment-service", "user_id": "alice", "memory": "VICTIM_ONLY_MEMORY: alice payment-service deploy host is pay-int-01" } ``` Attacker workspace object: ```json { "workspacePath": "/work/current", "canonical_workspace_path": "/srv/users/bob/attacker-repo", "user_id": "bob", "memory": "attacker session" } ``` Both objects produce the same application-level key: `sha256("/work/current").substring(0, 12)`. They are not security-equivalent because the canonical workspace path and user contexts differ. ## Impact This vulnerability allows attackers to: - Load another real project's persisted `MEMORY.md` into their agent context in shared path/shared `$HOME` environments (e.g., dev containers, CI workers, shared system accounts). - Expose sensitive project memory such as internal paths, service names, deployment notes, architecture summaries, and team conventions. - Poison future agent context by writing memory under a key later reused by another project. ## Proof of Concept The PoC script below proves the broken security invariant: two non-equivalent real workspaces share the same project-memory key because the key is derived only from the same lexical `workspacePath`. ```javascript #!/usr/bin/env node const fs = require('fs'); const os = require('os'); const path = require('path'); const crypto = require('crypto'); const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'mysti-memory-poc-')); const sharedHome = path.join(tmp, 'shared-home'); const victimRealProject = path.join(tmp, 'srv', 'users', 'alice', 'repo'); const attackerRealProject = path.join(tmp, 'srv', 'users', 'bob', 'repo'); const workDir = path.join(tmp, 'work'); const lexicalWorkspacePath = path.join(workDir, 'current'); fs.mkdirSync(sharedHome, { recursive: true }); fs.mkdirSync(victimRealProject, { recursive: true }); fs.mkdirSync(attackerRealProject, { recursive: true }); fs.mkdirSync(workDir, { recursive: true }); function projectMemoryPath(workspacePath) { const hash = crypto.createHash('sha256').update(workspacePath).digest('hex').substring(0, 12); return path.join(sharedHome, '.mysti', 'projects', hash, 'memory', 'MEMORY.md'); } try { // 1. Victim uses the shared lexical path fs.symlinkSync(victimRealProject, lexicalWorkspacePath, 'dir'); const victimMemoryPath = projectMemoryPath(lexicalWorkspacePath); fs.mkdirSync(path.dirname(victimMemoryPath), { recursive: true }); fs.writeFileSync( victimMemoryPath, '# Mysti Project Memory\n\n- VICTIM_ONLY_MEMORY: alice payment-service deploy host is pay-int-01\n' ); // 2. Attacker uses the same shared lexical path fs.unlinkSync(lexicalWorkspacePath); fs.symlinkSync(attackerRealProject, lexicalWorkspacePath, 'dir'); const attackerMemoryPath = projectMemoryPath(lexicalWorkspacePath); // 3. Attacker loads the memory const attackerObserved = fs.readFileSync(attackerMemoryPath, 'utf8'); console.log(JSON.stringify({ sameMemoryPath: victimMemoryPath === attackerMemoryPath, attackerLoadedVictimMemory: attackerObserved.includes('VICTIM_ONLY_MEMORY') }, null, 2)); } finally { fs.rmSync(tmp, { recursive: true, force: true }); } ``` *Observed execution output confirms `"attackerLoadedVictimMemory": true`.* ## Remediation Fix the project-memory identity construction in `src/managers/MemoryManager.ts` by canonicalizing the workspace identity and including explicit namespace/schema definitions. Example implementation direction: ```ts // Canonicalize the workspace identity and include security-relevant namespace fields const canonicalWorkspacePath = fs.realpathSync.native(workspacePath); const payload = JSON.stringify({ schema: 'mysti-project-memory-v2', userId: resolvedUserOrTenantId, canonicalWorkspacePath, }); const hash = crypto.createHash('sha256').update(payload).digest('hex'); ``` Additional mitigations: 1. Complete Field Coverage: Include fields relevant to user, tenant, remote workspace authority, canonical path, and memory schema. 2. Read-Time Revalidation: Store metadata beside `MEMORY.md` and verify that the current canonical workspace identity matches before loading memory into the context. 3. Avoid Truncation: Do not aggressively truncate digests used for persisted security-sensitive object identity (e.g., use the full SHA-256 hash). 4. State Invalidation: Migrate or clear existing `~/.mysti/projects/<hash>/memory` entries generated by affected versions. ## References - Vulnerable memory-key construction: `https://github.com/DeepMyst/Mysti/blob/bce0d2ba7904c056c576cf94db817635421d1f41/src/managers/MemoryManager.ts#L284-L288` - Project memory loading and writing: `https://github.com/DeepMyst/Mysti/blob/bce0d2ba7904c056c576cf94db817635421d1f41/src/managers/MemoryManager.ts#L297-L325` - Auto-memory prompt injection sink: `https://github.com/DeepMyst/Mysti/blob/bce0d2ba7904c056c576cf94db817635421d1f41/src/providers/ChatViewProvider.ts#L2642-L2645` - Workspace initialization path: `https://github.com/DeepMyst/Mysti/blob/bce0d2ba7904c056c576cf94db817635421d1f41/src/extension.ts#L85-L90`
Source⚠️ https://github.com/DeepMyst/Mysti/issues/46
User
 Dem00000 (UID 98563)
Submission06/01/2026 09:54 (1 month ago)
Moderation07/03/2026 16:09 (1 month later)
StatusAccepted
VulDB entry376119 [DeepMyst Mysti up to 0.4.0 Per-Project Auto-Memory MemoryManager.ts initProjectMemory workspacePath exposure of resource]
Points20

Do you know our Splunk app?

Download it now for free!