Skip to content

[Ubuntu 24.04][Security] DCode connect probe executes sandbox-user login profile before failing closed #8624

Closed

Description

@mercl-lau

Description

The DCode connect route probe executes a sandbox-user-created login profile before the managed probe command. The probe still fails closed, but the profile can emit output and create persistent side effects even though the managed boundary is intended to bypass user startup files.

Platform scope: Reproduced on Ubuntu 24.04 only; other platforms not tested

Regression: Unknown — earlier versions not tested

Environment

Device:        Ubuntu 24.04 test server
OS:            Ubuntu 24.04.4 LTS (Linux 6.8.0-124-generic)
Architecture:  x86_64
Node.js:       v22.23.1
npm:           10.9.8
Docker:        Docker Engine 29.5.3
OpenShell CLI: openshell 0.0.85
NemoClaw:      nemoclaw v0.0.104
OpenClaw:      N/A (LangChain Deep Agents Code sandbox)

Steps to Reproduce

  1. Onboard a fresh DCode sandbox named dcode-profile-probe and confirm that nemoclaw dcode-profile-probe connect --probe-only succeeds.
  2. As the sandbox user, create /sandbox/.bash_profile with a command that prints a recognizable marker, creates /sandbox/profile-ran, and exits successfully.
  3. As the sandbox user, create /sandbox/.curlrc with a trace-output directive.
  4. From the host, run nemoclaw dcode-profile-probe connect --probe-only and capture the exit code and output.
  5. Inspect the sandbox through the container administration boundary and check whether /sandbox/profile-ran exists.

Expected Result

The managed DCode route probe uses a neutral HOME, clears shell startup environment variables, and executes without a login shell. Sandbox-user .bash_profile, .bashrc, and .curlrc files are not evaluated, no marker or curl trace file is created, and the probe result reflects only the real inference route.

Actual Result

The command exits non-zero and reports:

Probe failed: LangChain Deep Agents Code could not reach the managed inference.local route in 'dcode-profile-probe'.

Container inspection after the command confirms that the login-profile marker was created. A direct managed-exec cleanup attempt also emits startup-profile output before the requested command, confirming that the sandbox-user login profile ran first.

Logs

Baseline probe: exit 0
Probe after planting the login profile: exit 1
Probe output: Probe failed: LangChain Deep Agents Code could not reach the managed inference.local route in 'dcode-profile-probe'.
Login-profile marker after probe: present
Curl trace marker after probe: absent

Activity

  1. added
    NV QABugs found by the NVIDIA QA Team
    needs: triageAwaiting maintainer classification
    on Aug 8, 2026
  2. added theissue type on Aug 8, 2026
  3. self-assigned this
    on Aug 10, 2026
  4. Dongni-Yang commented on Aug 10, 2026

    @Dongni-Yang
    Contributor

    The root cause of the login-profile execution is upstream in OpenShell, not in NemoClaw. I filed it as NVIDIA/OpenShell#2668.

    openshell sandbox exec never delivers argv to the sandbox as argv. It flattens the command vector and every --env pair into a single shell string (crates/openshell-server/src/grpc/sandbox.rs:1776-1798), relays that string over the supervisor SSH transport (stream_exec_over_relay, same file, 1800-1806), and the supervisor spawns it with a login shell (crates/openshell-supervisor-process/src/ssh.rs:992-996):

    |command| {
        let mut 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 PTY path does the same at 833-835. Both are unconditional, so no flag or environment value changes them.

    That explains the exact wording in this report — the profile runs before the managed probe command — and it means two mitigations already in the tree cannot work:

    • The dcode-managed-exec launcher cannot prevent it. The profile is sourced before the launcher's first instruction runs.
    • --env BASH_ENV= and --env ENV= cannot prevent it. They become command-prefix assignments inside the string handed to bash -lc, so they apply only after the login shell has already sourced the profile.

    Two observations on the existing behavior, both of which look correct as designed:

    • The probe failing after a profile is planted is intended. #6192 deliberately rejects contaminated probe evidence rather than parsing past it.
    • The managed route probe itself does not add a login shell; #6191 pins that argv.

    PR #8670 removes the one login shell I could attribute to NemoClaw in this flow: runAgentSmokeCommands wrapped Deep Agents Code smoke commands in sh -lc, nesting a second profile sourcing inside the managed boundary. It is reachable because a probe result with any stderr resolves to null rather than false (src/lib/actions/sandbox/inference-route-health.ts:53-62) and only an explicit false short-circuits (src/lib/actions/sandbox/terminal-connect-probe.ts:40), so an indeterminate route falls through to smoke.

    That PR is Refs, not Closes, on purpose. It is defense-in-depth. A planted /sandbox/.bash_profile will still run and still leave its marker until the upstream change lands, so this issue's "executes without a login shell" acceptance criterion is not reachable from NemoClaw today.

    Caveat on my evidence: I verified the upstream behavior by reading OpenShell main at 5e2f0d1, not by running it. This host cannot start a gateway, so I did not reproduce the sandbox-side execution directly.

    @mercl-lau one detail would help confirm the chain end to end: in your run, which command emitted the startup-profile output — the route probe, the smoke command, or the direct dcode-managed-exec cleanup?

    Signed-off-by: Dongni Yang [email protected]

  5. added
    area: sandboxOpenShell sandbox lifecycle, runtime, config, or recovery
    area: securitySecurity controls, permissions, secrets, or hardening
    integration: dcodeLangChain Deep Code integration behavior
    platform: ubuntuAffects Ubuntu Linux environments
    and removed
    needs: triageAwaiting maintainer classification
    on Aug 10, 2026
  6. added a commit that references this issue on Aug 13, 2026
    5e7d8a0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

NV QABugs found by the NVIDIA QA Teamarea: sandboxOpenShell sandbox lifecycle, runtime, config, or recoveryarea: securitySecurity controls, permissions, secrets, or hardeningintegration: dcodeLangChain Deep Code integration behaviorplatform: ubuntuAffects Ubuntu Linux environments

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions