# P8-016: Security — Tool Path Hardening + Sandbox Escape Prevention ## Status: in-progress ## Branch: feat/p8-016-tool-hardening ## Issue: #169 ## Scope Harden file, git, and shell tool factories so no path operation escapes `sandboxDir`. ## Files to Create - `apps/gateway/src/agent/tools/path-guard.ts` (new) - `apps/gateway/src/agent/tools/path-guard.test.ts` (new) ## Files to Modify - `apps/gateway/src/agent/tools/file-tools.ts` - `apps/gateway/src/agent/tools/git-tools.ts` - `apps/gateway/src/agent/tools/shell-tools.ts` ## Analysis ### file-tools.ts - Has existing `resolveSafe()` function but uses weak containment check (relative path) - Replace with `guardPath` (for reads/lists on existing paths) and `guardPathUnsafe` (for writes) - Error pattern: return `{ content: [{ type: 'text', text: 'Error: ...' }], details: undefined }` ### git-tools.ts - Has `clampCwd()` that silently falls back to sandbox root on escape attempt - Replace with strict `guardPath` that throws SandboxEscapeError, caught and returned as error - Also need to guard the `path` parameter in `git_diff` ### shell-tools.ts - Has `clampCwd()` same silent-fallback approach - Replace with strict `guardPath` that throws SandboxEscapeError ## Key Design Decisions - `guardPath`: uses `realpathSync.native` to resolve symlinks, requires path to exist - `guardPathUnsafe`: lexical only (`path.resolve`), for paths that may not exist yet - Both throw `SandboxEscapeError` on escape attempt - Callers catch and return error result ## Verification - pnpm typecheck - pnpm lint - pnpm format:check - pnpm test