You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A delegated child of a scheduled task runs unconfined #2477
A session spawned by the subagent or boss tool inherits its sandbox tier by reading the parent session object (emrg/server/daemon.py, child.set_sandbox(parent.sandbox)). A scheduled task's tier is not there. It is resolved from tasks.yml into the request (emrg/server/scheduler.py, _resolve_sandbox → the task message → TaskRequest.sandbox), and the only writers of a tier onto a session are the client handler _handle_set_sandbox and those two inheritance sites.
So a task running at workspace-write — what a task gets when it declares nothing — has parent.sandbox is None: the child inherits nothing, its own tool calls carry no tier, and a call that carries no tier resolves to policy.DEFAULT_MODE, which is danger-full-access. A delegated child can write where the task that spawned it may not. The boss case is the sharper one, because the owner is the session whose answer the executor then acts on.
Measured on a clean checkout by running the same delegation twice:
a parent session with set_sandbox("read-only") → the child stored read-only;
a parent session with no tier, the turn carrying read-only → the child stored None.
The existing test for this rule sets the tier on the session before delegating, so it models a client's session and never reaches the task shape.
What the fix must satisfy
The tier a child runs at is the tier the spawning turn runs under — req.sandbox, the same value the turn's own shell and write calls are injected with — falling back to the session's tier when the turn declared none.
That tier reaches the tool through the daemon's argument injection, unconditionally, exactly as the parent's session and tool set already do: a tier the model can name for its own child is not a boundary.
Silence keeps its meaning: when neither the turn nor the session declares a tier, the child stays unconfined.
Guarded at the seam that broke. A test must drive _inject_tool_arguments and then the tool — for both subagent and boss — and must fail on the unfixed tree; a test that hands the tier straight to the runner would stay green either way.
Activity
argszero commentedon Oct 22, 2026
Handled by #2478