Skip to content

Hardened defaults: template + README pass #23

@haard

Description

@haard

Bundle of template- and docs-only changes surfaced by a sandbox breakout audit. No code-behavior changes.

1. Make the template's default home an allowlist

Simplest and strongest change. The current logic already supports this — blacklist applies tmpfs, whitelist (now ro as of 202604.4.1a0) binds specific paths back read-only, writable binds rw, and all of them are applied after the initial --ro-bind $HOME $HOME, so later args override. Shift the template from:

blacklist = [
    "~/.ssh", "~/.gnupg", "~/.aws", "~/.kube", "~/.config/gcloud",
    "~/.azure", "~/.docker", "~/.npmrc", "~/.pypirc", "~/.boto", "/mnt",
]

to:

blacklist = [
    "~",                              # deny-by-default home
    "/mnt",                           # WSL Windows drives (cmd.exe/powershell interop escape)
]
whitelist = [                         # read-only exceptions (dotfiles a shell needs)
    "~/.gitconfig",
    "~/.config/fish",                 # or "~/.bashrc" / "~/.zshrc" depending on shell
    "~/.terminfo",
    "~/.local/share/fish",            # fish history + functions; adjust per shell
]

This closes the whole class of "tool X added a credential file we forgot to blacklist" regressions (#24 folded in here). Supersedes items (3) below — with ~ blacklisted, .claude.json/.bash_history/.age/.config/op/.config/pypoetry/.config/uv are all hidden by default with no enumeration needed.

Action needed: figure out the minimum whitelist set that keeps a typical fish / bash / zsh login functional — probe empirically.

2. Move ~/.pyenv/shims from writable to whitelist

Template currently suggests writable = ["~/.pyenv/shims"]. Shims only need read+exec to run; write access inside the sandbox is a persistent-code-execution vector (drop a shim, host picks it up next time the user runs python outside the sandbox).

Now that whitelist is read-only, move pyenv to a read-only whitelist entry — or at minimum add a warning comment that writable grants host-writable access.

3. (Obsoleted by (1))

Previously: expand the enumerated blacklist with .claude.json, .bash_history, .age, .config/op, .config/pypoetry, .config/uv. Unnecessary if (1) lands — blacklisting ~ covers all of them and every future credential file too.

4. Recommend clean_env = true in template

Probe caught ANTROPIC_API_KEY (note the typo — treat as real and rotate, or label as decoy) and CODESTRAL_API_KEY leaking from host env into the sandbox. clean_env already exists and clears everything but PATH/HOME/USER/SHELL/TERM/LANG, then re-adds from [env]. Template currently has it commented out.

Uncomment it and make clean_env = true the template default; document the [env] pass-through pattern.

5. README: WSL-specific guidance

/etc/resolv.conf on WSL is a symlink into /mnt/wsl, so users blacklisting /mnt need to whitelist something back or DNS breaks. Current template comment suggests whitelist = ["/mnt/wsl"] — too broad; that tree contains Docker Desktop sockets and other host-reachable surfaces.

Change the template recommendation and README to:

whitelist = ["/mnt/wsl/resolv.conf"]

If the user needs wslg (GUI apps), suggest "/mnt/wslg" rather than the /mnt/wsl parent.

Scope

All template/README edits. No behavioral change, no new config keys. Should land as one commit on a dedicated branch.

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