Skip to content

ToolContext defaults permission_context to bypassPermissions — silently disables workspace allowlist #168

@ericleepi314

Description

@ericleepi314

File

`src/tool_system/context.py:67-71`

@dataclass
class ToolContext:
    workspace_root: Path
    permission_context: ToolPermissionContext = field(
        default_factory=lambda: ToolPermissionContext(mode=\"bypassPermissions\")
    )

Repro

Two failing parity tests on `main` (HEAD `e1832a0`):

$ .venv/bin/pytest tests/parity/test_e2e_edit_flow.py::TestE2EWriteFlow::test_write_outside_workspace_blocked
E   AssertionError: ToolPermissionError not raised
$ .venv/bin/pytest tests/parity/test_e2e_file_read.py::TestE2EFileRead::test_read_outside_workspace_blocked
E   AssertionError: ToolPermissionError not raised

Both tests construct `ToolContext(workspace_root=self.root)` without an explicit `permission_context` and dispatch a Write/Read to a path outside `self.root`. They expect a `ToolPermissionError`. Today the dispatch succeeds because the default permission mode bypasses every check — including the working-dir allowlist added in PR #128.

Impact

Any in-process caller that constructs `ToolContext` without explicitly setting `permission_context` (SDK callers, tests, programmatic embedders) silently gets full `bypassPermissions`. The workspace-root sandbox is opt-in by accident.

This is a silent security regression: documented `workspace_root` guards are bypassed unless every call site remembers to pass an explicit `ToolPermissionContext(mode="default")`.

Fix sketch

Default `permission_context` to `ToolPermissionContext(mode="default")`. Audit call sites that relied on the implicit bypass (subagent fork path, `dangerous-skip-permissions` tests, headless entrypoints) and pass an explicit `bypassPermissions` context where intentionally needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions