Agents run over SSH only; put the hardening back
The local sandbox is dropped before it was built. Every hard problem in it came from running on the machine that holds the database and the encryption key: the service user cannot traverse /home, granting it needs ACLs, RLIMIT_NPROC is counted per uid so a fork bomb starves the server too, --size only applies to tmpfs so there is no disk quota, and the bind list is a standing invitation to widen until the sandbox is decoration. Over SSH, isolation is somebody's considered choice of host -- a throwaway container with one project mounted into it -- using tools far better at it than anything that could be built here. It is also the only version that is honestly multi-user: each person brings their own credentials and their own machine, and picks a project directory on it. So ProtectKernelTunables goes back. It was removed for exactly one reason, that bubblewrap cannot mount /proc without it, and that reason is gone. The agents settings group loses everything bwrap-shaped with it. What this costs, and the admin copy has to say so: there was a network:False switch that made exfiltration from a compromised reply impossible, and over SSH there is no equivalent, because the network belongs to the far side. The security of an agent chat is now the security of the host behind its profile, and LLeMbas cannot tell a scratch container from a live server. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -46,48 +46,29 @@ def _general_defaults() -> dict[str, Any]:
|
||||
|
||||
|
||||
def _agents_defaults() -> dict[str, Any]:
|
||||
"""Agentic execution: running commands, on this machine or over SSH.
|
||||
"""Agentic execution: running commands on a machine reached over SSH.
|
||||
|
||||
Local execution is an instance decision rather than a personal one, because
|
||||
the sandbox runs on this machine and its blast radius is this machine. SSH
|
||||
profiles belong to whoever made them, but whether SSH exists here at all
|
||||
does not.
|
||||
|
||||
Everything is off until an administrator turns it on. That is not caution
|
||||
for its own sake: a model reads web pages, files and command output, all of
|
||||
which are untrusted, so shell access is a capability somebody has to choose
|
||||
on purpose.
|
||||
Deliberately never on the machine LLeMbas runs on. Executing here would put
|
||||
the blast radius on the host holding the database and the encryption key,
|
||||
and buying it back needs a sandbox, a bind list, a second unix account and
|
||||
an argument about every one of them. Over SSH, isolation is somebody's
|
||||
considered choice of host -- a throwaway container with one project mounted
|
||||
into it, or a VM -- made with tools far better at it than anything that
|
||||
could be built here.
|
||||
"""
|
||||
return {
|
||||
"local_enabled": False,
|
||||
"ssh_enabled": False,
|
||||
"bwrap_path": "bwrap",
|
||||
# Read-only paths every sandbox sees, on top of /usr and the /lib
|
||||
# symlinks. The deployment prefix is never here, and a bind containing
|
||||
# the data directory is refused when the sandbox is built rather than
|
||||
# trusted to a careful administrator.
|
||||
"ro_binds": [
|
||||
"/etc/ssl",
|
||||
"/etc/ca-certificates",
|
||||
"/etc/resolv.conf",
|
||||
# /etc/resolv.conf is a symlink into here on a systemd-resolved box,
|
||||
# and binding the symlink alone leaves it dangling.
|
||||
"/run/systemd/resolve",
|
||||
],
|
||||
# Off by default, and the single most valuable setting in this group: an
|
||||
# instruction injected through a file the model read cannot send
|
||||
# anything anywhere from a sandbox with no network.
|
||||
"network": False,
|
||||
# Off until an administrator turns it on. Not caution for its own sake:
|
||||
# a model reads web pages, files and command output, all of them
|
||||
# untrusted, so a shell is a capability somebody chooses on purpose.
|
||||
"enabled": False,
|
||||
# Per command.
|
||||
"default_timeout": 60,
|
||||
"max_timeout": 600,
|
||||
"max_output_bytes": 64 * 1024,
|
||||
"ulimit_fsize_mb": 64,
|
||||
"ulimit_nproc": 128,
|
||||
# Per reply. See services/agent/policy.py:Limits.
|
||||
"max_steps": 40,
|
||||
"max_wall_seconds": 900,
|
||||
"max_total_output_bytes": 1024 * 1024,
|
||||
"workspace_max_bytes": 512 * 1024 * 1024,
|
||||
# How long a reply waits for someone to answer. Clamped on read: a zero
|
||||
# here would park a background task forever.
|
||||
"approval_timeout": 900,
|
||||
|
||||
Reference in New Issue
Block a user