Skip to content

Windows: no OS-level sandbox, so command scanning is the only boundary #43

Description

@cf-pages

Problem

On Linux, safe mode has two independent layers: Landlock confines the filesystem at the kernel level, and the command scans (DESTRUCTIVE_RE, NETWORK_RE, and friends) are defense-in-depth on top of it.

On Windows there is no such layer. A search of the codebase finds no job object, restricted token, or AppContainer usage — the text scans are the only thing standing between a command and the host.

That's structurally unsound, because static analysis of a shell command is not decidable. #37 is a concrete instance: PowerShell resolves commands at runtime, so $c='Invoke-WebRequest'; & $c example.com names no cmdlet and passes every scan. We fixed that by gating dynamic syntax behind a permission, which restores the "text is literal" precondition the scans need — but that is a narrower boundary, not a real one, and the same class of problem will keep appearing for any shell we support.

What the ecosystem does

Both major agents treat authorization and isolation as separate axes, and put the security boundary in the OS:

  • Codex ships a mandatory OS-native sandbox on Linux, macOS, and Windows.
  • Claude Code uses bubblewrap+seccomp on Linux, Seatbelt on macOS, and Job Objects on Windows. Its static command parser exists only to decide whether to skip an approval prompt when the sandbox is already on — when the parser can't analyze something it prompts, and the sandbox still contains the command either way.

In other words, nobody relies on command-text matching as the boundary. Blacklists survive only as a thin always-on check for catastrophic commands (rm -rf /).

Proposal

Add OS-level confinement for exec_command on Windows — job object plus a restricted token, or AppContainer — with the same filesystem read/write roots the Landlock path already computes (landlock_write_roots(), guard_allow_roots()).

Once that exists:

  • The command scans can be demoted to defense-in-depth on Windows, matching Linux.
  • The safe-mode PowerShell dynamic-syntax gate added in Windows: execute string commands with PowerShell 7 #37 could be relaxed, because a command the parser can't analyze would still be contained.
  • The shell choice (pwsh vs cmd) stops being a security decision and becomes an ergonomics one — pwsh would still be preferred for UTF-8 output determinism, but a documented cmd fallback would no longer be dangerous.

Related: #36 (Windows runtime work), #37.

Interim state

Until this lands, docs/limitations.md states plainly that Windows safe mode is a best-effort gate rather than a boundary.

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