Skip to content

Built-in file tools are cwd-contained regardless of the execution boundary, making "full access" stricter than ask mode #2083

Description

@Astro-Han

What happened

In a Desktop session with the "full access" permission mode (permissionMode: bypass), the Write tool rejects any path outside the session cwd:

Write path must stay inside session cwd "/Users/.../maka-agent"; received "/tmp/pr-body-en.md".

The same session's Bash tool writes to /tmp without complaint, and an ordinary ask session is allowed to write that exact path. Enabling full access makes the built-in file tools more restrictive than the default mode.

Root cause: path admission has two independent authorities.

  • Declared policy — PermissionProfile. workspace-write grants write to :workspace_roots, :tmpdir and :slash_tmp (packages/core/src/permission-profile.ts:137); bypass compiles to danger-full-access, i.e. unrestricted (packages/core/src/permission-profile-compiler.ts:39). This is enforced by the filesystem worker via canWritePath/canReadPath (packages/runtime/src/filesystem-worker/client.ts:187).
  • Undeclared policy — LocalWorkspaceExecutor.assertInsideCwd (packages/runtime/src/workspace-executor.ts:351) hard-codes "inside session cwd" with no permission input at all.

The second is stricter than every declared profile. It normally stays invisible because managed boundaries route through the worker; filesystemWorkerForExecution skips the worker for bypass/external boundaries (packages/runtime/src/builtin-tools.ts:697), leaving the hard-coded rule as the only arbiter. A third, permission-blind check exists for Glob patterns (assertRelativeGlobPattern, packages/runtime/src/builtin-tools.ts:1226).

Resulting behavior for /tmp/pr-body-en.md:

Mode Boundary Arbiter Write Bash
ask / execute managed worker + workspace-write allowed allowed
bypass (full access) bypass hard-coded cwd containment rejected allowed

All built-in file tools share the fallback and the restriction: Read (:344), Write (:408), Edit (:471), FormatJson (:538), Glob (:621), Grep (:668). The Write tool description ("Absolute paths and parent traversal are rejected", :371) documents this legacy behavior and is already untrue for managed sessions.

How to reproduce

  1. Open a Desktop session and set the permission mode to full access.
  2. Ask the agent to Write to an absolute path outside the session cwd, e.g. /tmp/pr-body-en.md.
  3. The tool call fails with the message above.
  4. In the same session, run printf hi > /tmp/pr-body-en.md through Bash — it succeeds.
  5. Switch to ask mode and repeat step 2 — the write is allowed by the workspace-write profile.

Environment

  • Maka commit: d3b0bc8
  • OS: macOS (Darwin 25.5.0)
  • Surface: Desktop (the same fallback is reachable from CLI/Headless)
  • Node.js: workspace default

Logs, screenshots, or additional context

Fix direction — make the ExecutionBoundary the single authority and demote executors to mechanism:

  • Introduce one boundary-aware FilesystemExecutor contract; compose it per boundary (managedFilesystemWorkerClient, bypass → local host execution, external → isolated backend, never a silent host fallback).
  • Remove filesystemWorkerForExecution and the duplicated branch in all six file tools; drop assertInsideCwd/assertRelativeGlobPattern as policy; split the file facets out of WorkspaceExecutor, which keeps process execution.
  • Keep the headless isolated adapter's containment as a transport invariant and have it explicitly reject host-scoped requests.
  • Update the Write/Glob descriptions to state boundary-dependent access.
  • Verify with a parameterized conformance suite over Read/Write/Edit/FormatJson/Glob/Grep × {managed, bypass, external}, plus Bash parity and the existing symlink/TOCTOU escape regressions.

Diagnosis was cross-checked with two independent external reviews; all three agree on the cause and on the boundary-as-sole-authority fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions