Guest-Path Translation for Tool Permissions in Claude Desktop Cowork Mode
The Claude Desktop Debian package implements guest-path translation in scripts/cowork-vm-service.js to convert VM-internal paths like /sessions/1234/mnt/.auto-memory into host-resolvable paths before granting tool permissions, preventing directory-traversal attacks while maintaining functional isolation.
When running Claude Desktop in Cowork mode, the Electron frontend spawns tools inside an isolated VM backend. These tools receive arguments containing guest-side paths that the host filesystem cannot access directly. The aaddrick/claude-desktop-debian repository solves this through a dedicated translation layer that maps guest paths to host paths before the daemon spawns any process.
Why Guest-Path Translation Matters
The Cowork VM backend isolates user code for security, but this isolation creates a path mismatch. When the frontend requests tool permissions like Node(/sessions/abc123/mnt/.auto-memory), the VM-internal path /sessions/... does not exist on the host filesystem.
Without translation, the spawned tool would receive invalid paths, causing permission failures or exposing the host to path-traversal vulnerabilities if unvalidated guest input reaches the filesystem. The translation layer ensures every path is validated, resolved, and confined to authorized mount points before execution.
Core Translation Functions in cowork-vm-service.js
The translation logic resides in scripts/cowork-vm-service.js and consists of three coordinated functions that handle different stages of argument sanitization.
translateGuestPath(): Single Path Resolution
translateGuestPath(guestPath, mountMap) converts a single guest path to its host equivalent. This function validates that the path starts with /sessions/, extracts the mount name (e.g., .auto-memory), and looks up the corresponding host directory in mountMap.
Key implementation details from lines 162‑196:
- Validates the
/sessions/prefix to ensure the path originates from the guest VM - Extracts the mount name and any trailing sub-path
- Checks
mountMapfor the mount name, with fallback checks for.${name}and stripped leading dots for compatibility - Joins the host base with the sub-path, resolves it, and blocks path-traversal attempts outside the mount
- Returns the normalized host path or
nullon failure
translateEmbeddedGuestPaths(): CSV Tool List Processing
translateEmbeddedGuestPaths(csv, mountMap) handles tool-permission CSV strings like Tool(path) that appear in flags such as --allowedTools or --disallowedTools. This function scans the CSV, identifies guest paths inside parentheses, and translates them while preserving the surrounding tool names.
Implementation from lines 382‑406:
- Splits the CSV using
splitToolList - For each
Tool(pattern)entry, normalizes leading slashes and checks for the/sessions/prefix - Calls
translateGuestPathfor valid guest paths - Rebuilds entries as
Tool(hostPath)on success, or drops them on failure - Returns the rebuilt CSV string with only valid, translated paths
cleanSpawnArgs(): Full Argument Sanitization
cleanSpawnArgs(rawArgs, mountMap) produces the final sanitized argument vector for the spawned tool. This function iterates over rawArgs and applies different translation strategies based on flag types.
Implementation from lines 418‑452:
- Detects single-path flags like
--add-dirand--plugin-dir, callingtranslateGuestPathand discarding the flag/value pair if translation fails - Detects tool-list flags like
--allowedToolsand--disallowedTools, delegating totranslateEmbeddedGuestPathsto remove only invalid entries while keeping the flag - Handles plugin directory resolution via
resolvePluginRootfor--plugin-dirspecifically
Building the Mount Map
The translation functions depend on mountMap, which is constructed in buildMountMap (around line 221) immediately before spawning a tool. This map combines:
- Mount binds: Explicit host-to-guest bindings supplied by the user
- Additional mounts: Front-end requested mounts like
.auto-memoryand.skills
buildMountMap validates that every resolved host path remains inside the user’s $HOME directory, rejecting any mount that would escape the home folder. This validation prevents the VM from accessing sensitive system paths even if the frontend requests them.
Security Safeguards
The guest-path translation layer implements multiple security controls to prevent sandbox escapes:
Path Traversal Prevention: translateGuestPath resolves the final joined path and verifies it remains within the authorized mount base directory. Any attempt to traverse upward with .. sequences results in the function returning null and the path being dropped from arguments.
Prefix Validation: All guest paths must begin with /sessions/ to be considered valid. This prevents the frontend from injecting arbitrary host paths directly.
Mount Scope Enforcement: buildMountMap restricts all mounts to the user’s home directory, ensuring the VM cannot access system directories like /etc or /usr even through indirect translation.
Silent Failure for Invalid Paths: Rather than crashing or passing through unvalidated paths, the translation functions return null or drop entries. This ensures tools only receive valid, resolvable host paths.
Practical Examples
The following examples demonstrate how the translation functions process real-world inputs.
Translating a CSV of Tool Permissions
// Example CSV coming from the front-end:
const csv = 'Git,Node(/sessions/abc123/mnt/.auto-memory),Shell';
// Assume a mount map where ".auto-memory" points to the host's ~/.auto-memory
const mountMap = {
'.auto-memory': '/home/you/.auto-memory',
'.skills': '/home/you/.skills',
};
const translated = translateEmbeddedGuestPaths(csv, mountMap);
console.log(translated);
// → "Git,Node(/home/you/.auto-memory),Shell"
The function drops any entry whose guest path cannot be resolved, preventing a tool from receiving an impossible permission rule.
Cleaning a Full Argument List for a Tool Spawn
const rawArgs = [
'--add-dir', '/sessions/abc123/mnt/.skills',
'--allowedTools', 'Git,Node(/sessions/abc123/mnt/.auto-memory),Shell',
'--plugin-dir', '/sessions/abc123/mnt/.plugins',
];
const clean = cleanSpawnArgs(rawArgs, mountMap);
console.log(clean);
/*
[
'--add-dir', '/home/you/.skills',
'--allowedTools', 'Git,Node(/home/you/.auto-memory),Shell',
'--plugin-dir', '/home/you/.plugins' // resolved via resolvePluginRoot inside cleanSpawnArgs
]
*/
If any path cannot be mapped, the corresponding flag/value pair is silently omitted, ensuring the spawned process never receives an invalid path.
End-to-End Spawn Request (Simplified)
// Simulated request payload from the Electron UI
const request = {
cwd: '/sessions/abc123/mnt/.skills/project',
args: ['--add-dir', '/sessions/abc123/mnt/.skills', '--allowedTools', 'Node(/sessions/abc123/mnt/.auto-memory)'],
env: { CLAUDE_CONFIG_DIR: '/sessions/abc123/mnt/.config' },
additionalMounts: { '.auto-memory': { path: '.auto-memory' }, '.skills': { path: '.skills' } },
mountBinds: [] // none in this simple case
};
// 1️⃣ Build mount map
const mountMap = buildMountMap(request.additionalMounts, request.mountBinds);
// 2️⃣ Resolve working directory
const workDir = resolveWorkDir(request.cwd, null, mountMap);
// 3️⃣ Clean args & env
const cleanArgs = cleanSpawnArgs(request.args, mountMap);
const mergedEnv = buildSpawnEnv(request.env, mountMap);
// 4️⃣ Finally spawn (pseudo-code)
spawnTool({ cwd: workDir, args: cleanArgs, env: mergedEnv });
Every step leverages the translation helpers, guaranteeing that the child process only sees host-side paths.
Summary
- Guest-path translation converts VM-internal paths like
/sessions/.../mnt/.auto-memoryto host-resolvable paths before spawning tools in Claude Desktop's Cowork mode. - The translation logic lives in
scripts/cowork-vm-service.js, specifically intranslateGuestPath,translateEmbeddedGuestPaths, andcleanSpawnArgs. - Security controls include path-traversal blocking,
/sessions/prefix validation, and home-directory scope enforcement viabuildMountMap. - The system silently drops invalid paths rather than passing them through, ensuring tools only receive valid host-side resources.
- Enable
COWORK_VM_DEBUGto inspect translation decisions during permission failures.
Frequently Asked Questions
How does Claude Desktop prevent path traversal attacks during guest-path translation?
The translateGuestPath function in scripts/cowork-vm-service.js resolves the final joined path and verifies it remains within the authorized mount base directory. If the resolved path escapes the mount root via .. sequences or symbolic links, the function returns null and the path is dropped from the tool's arguments. Additionally, buildMountMap restricts all mounts to the user's $HOME directory, preventing access to system paths like /etc or /usr.
What happens if a guest path cannot be translated to a host path?
Rather than crashing or passing the invalid path through, the translation functions implement silent failure. translateGuestPath returns null for unmappable paths. When processing CSV tool lists via translateEmbeddedGuestPaths, entries containing invalid guest paths are removed entirely from the output string. In cleanSpawnArgs, failure to translate a single-path flag like --add-dir results in the entire flag-value pair being omitted from the final argument vector.
Which environment variables and arguments undergo guest-path translation?
The translation pipeline processes several specific parameters in scripts/cowork-vm-service.js. Argument flags including --add-dir, --plugin-dir, --allowedTools, and --disallowedTools are scanned for guest paths. Environment variables CLAUDE_CONFIG_DIR and CLAUDE_COWORK_MEMORY_PATH_OVERRIDE are processed by buildSpawnEnv to translate any embedded guest paths. The working directory specified in spawn requests is also resolved via resolveWorkDir, which may invoke translateGuestPath for guest-relative paths.
Where can I find the test suite for guest-path translation logic?
The Bats test suite for validating translation functions is located at tests/cowork-path-translation.bats in the repository. This file contains test cases covering various mount map configurations, edge cases for path traversal attempts, and validation of the CSV parsing logic used in translateEmbeddedGuestPaths. Running these tests ensures that modifications to scripts/cowork-vm-service.js maintain the security and functional guarantees of the translation layer.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →