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
Investigated from a source read of main at 5e2f0d1, not from a live cluster (this host cannot run a gateway — glibc 2.31, below the 2.32 minimum).
Searched existing issues for exec login shell profile: no matching issue found.
Latest release checked: v0.0.101. The code path below is unchanged on main at 5e2f0d1.
Traced the full sandbox exec path rather than reproducing, because the behavior is unconditional in source:
handle_exec_sandbox builds a command string from the request, flattening argv and prepending --env pairs as shell assignments — crates/openshell-server/src/grpc/sandbox.rs:1776-1798.
It relays that string over the supervisor SSH transport — stream_exec_over_relay, crates/openshell-server/src/grpc/sandbox.rs:1800-1806.
The supervisor spawns it under a login shell — spawn_pipe_exec, crates/openshell-supervisor-process/src/ssh.rs:967 and 992-996.
Confirmed the PTY path does the same at crates/openshell-supervisor-process/src/ssh.rs:833-835.
sandbox exec runs every command through /bin/bash -lc, so the sandbox user's .profile / .bash_profile / .bashrc are sourced before the requested command starts.
// crates/openshell-supervisor-process/src/ssh.rs:992-996
|command| {letmut c = Command::new("/bin/bash");// Use login shell (-l) so that .profile/.bashrc are sourced and// tool-specific env vars (VIRTUAL_ENV, UV_PYTHON_INSTALL_DIR, etc.)// are available without hardcoding them here.
c.arg("-lc").arg(command);
c
}
The intent is clear and reasonable for interactive and tool-discovery use. The problem is that there is no way to opt out, which makes sandbox exec unsuitable for a managed or trusted probe:
Argv is not preserved.build_remote_exec_command joins argv into a single shell string, so a caller passing exact argv after -- still gets shell evaluation.
A trusted launcher cannot defend itself. A caller that execs a root-owned, mode-0755 helper still has the user's startup files run before that helper's first instruction.
--env cannot suppress it.--env BASH_ENV= and --env ENV= become command-prefix assignments inside the string passed to bash -lc, so they apply only after the login shell has already sourced the profile.
Consequences for a caller that needs a trusted result:
Output integrity. A startup file writing to stdout/stderr interleaves with the command's output, so a caller parsing that output cannot distinguish command evidence from user-controlled text.
Side effects. A startup file executes on every exec, so it can create files or mutate state even when the requested command is read-only and the caller's boundary intends to bypass user startup files.
Reproduction Steps
Create a sandbox and, as the sandbox user, write /sandbox/.bash_profile:
Observe PROFILE-RAN on stderr, and /sandbox/profile-ran present, even though the requested command is /bin/sh -c 'printf OK' and both startup variables were cleared.
Environment
OS: Ubuntu 24.04 (downstream report), source read on Ubuntu 20.04
OpenShell: v0.0.85 in the downstream report; behavior verified unchanged in source on main at 5e2f0d1, and v0.0.101 is the latest release
Given #556, the least invasive option that still fixes this:
An explicit opt-out on ExecSandboxRequest, for example login_shell: bool defaulting to today's behavior, so every existing caller is unaffected and only a caller that asks for a clean environment gets one.
Alternatively, keep the login shell but apply request environment entries to the shell process itself rather than as command-prefix assignments, so BASH_ENV= and ENV= are honored before startup files are sourced. This is smaller, but it does not address .profile sourcing from -l, so it only partly fixes the problem.
I am happy to send a PR for whichever direction you prefer.
Agent Diagnostic
Investigated from a source read of
mainat5e2f0d1, not from a live cluster (this host cannot run a gateway — glibc 2.31, below the 2.32 minimum).exec login shell profile: no matching issue found.mainat5e2f0d1.sandbox execpath rather than reproducing, because the behavior is unconditional in source:handle_exec_sandboxbuilds a command string from the request, flattening argv and prepending--envpairs as shell assignments —crates/openshell-server/src/grpc/sandbox.rs:1776-1798.stream_exec_over_relay,crates/openshell-server/src/grpc/sandbox.rs:1800-1806.spawn_pipe_exec,crates/openshell-supervisor-process/src/ssh.rs:967and992-996.crates/openshell-supervisor-process/src/ssh.rs:833-835./sandbox/.bash_profileran and left a marker file during a managed probe that passes exact argv and setsBASH_ENV=/ENV=to empty.Description
sandbox execruns every command through/bin/bash -lc, so the sandbox user's.profile/.bash_profile/.bashrcare sourced before the requested command starts.The intent is clear and reasonable for interactive and tool-discovery use. The problem is that there is no way to opt out, which makes
sandbox execunsuitable for a managed or trusted probe:build_remote_exec_commandjoins argv into a single shell string, so a caller passing exact argv after--still gets shell evaluation.--envcannot suppress it.--env BASH_ENV=and--env ENV=become command-prefix assignments inside the string passed tobash -lc, so they apply only after the login shell has already sourced the profile.Consequences for a caller that needs a trusted result:
Reproduction Steps
Create a sandbox and, as the sandbox user, write
/sandbox/.bash_profile:From the host, run a command with exact argv and the shell startup variables cleared:
Observe
PROFILE-RANon stderr, and/sandbox/profile-ranpresent, even though the requested command is/bin/sh -c 'printf OK'and both startup variables were cleared.Environment
mainat5e2f0d1, and v0.0.101 is the latest releaseRelated issues
not plannedon 2026-05-01. I am not re-proposing that design here. This issue asks only for a way to opt out of profile sourcing, which does not require changing the transport./bin/bashand break BYOC images without Bash. A fix there and a fix here touch the same lines, so they may be worth solving together.Suggested direction
Given #556, the least invasive option that still fixes this:
ExecSandboxRequest, for examplelogin_shell: booldefaulting to today's behavior, so every existing caller is unaffected and only a caller that asks for a clean environment gets one.environmententries to the shell process itself rather than as command-prefix assignments, soBASH_ENV=andENV=are honored before startup files are sourced. This is smaller, but it does not address.profilesourcing from-l, so it only partly fixes the problem.I am happy to send a PR for whichever direction you prefer.