Skip to content

Telegram bridge bypasses OpenShell credential isolation — raw NVIDIA_API_KEY injected into sandbox via SSH #1108

@zredlined

Description

@zredlined

Summary

The Telegram bridge in scripts/telegram-bridge.js:108 SSHs into the sandbox and passes NVIDIA_API_KEY as a plaintext shell environment variable:

const cmd = `export NVIDIA_API_KEY=${shellQuote(API_KEY)} && nemoclaw-start openclaw agent ...`;
const proc = spawn("ssh", ["-T", "-F", confPath, `openshell-${SANDBOX}`, cmd], { ... });

This bypasses the OpenShell provider system's credential isolation mechanism, which is specifically designed to prevent real secrets from ever existing as readable strings inside the sandbox.

How OpenShell credential isolation works

OpenShell's provider system (openshell provider create) stores credentials server-side in the gateway. When a sandbox starts, the runtime:

  1. Fetches credential values from the gateway via gRPC (GetSandboxProviderEnvironment)
  2. Replaces every real value with an opaque placeholder (e.g., NVIDIA_API_KEY=openshell:resolve:env:NVIDIA_API_KEY) in the child process environment
  3. When the sandbox process makes an HTTP request containing a placeholder in a header value, the L7 proxy rewrites the placeholder to the real secret only in the outbound bytes on the wire

The real credential never exists as a readable string inside the sandbox. printenv, /proc/self/environ, and ps aux all show only the placeholder.

Relevant OpenShell source:

  • crates/openshell-sandbox/src/secrets.rsSecretResolver::from_provider_env() splits credentials into placeholders + real values
  • crates/openshell-sandbox/src/process.rs:119-120scrub_sensitive_env() then inject_provider_env() with placeholders only
  • crates/openshell-sandbox/src/l7/relay.rs:282relay_http_request_with_resolver rewrites headers at the wire level

What the Telegram bridge does instead

The bridge runs on the host and SSHes into the sandbox with the raw key embedded in the command string. This means:

  • The real NVIDIA_API_KEY is visible in ps aux on both host and sandbox
  • The key is exported as a plain env var readable by any process in the sandbox
  • A compromised agent can exfiltrate it through any allowed egress path
  • write_auth_profile in nemoclaw-start.sh:87-107 writes an auth profile referencing this env var, creating a second readable path to the credential

This directly undoes the correct behavior already present in the onboarding flow (onboard.js:1801-1809), which explicitly deletes NVIDIA_API_KEY from the sandbox environment.

Relationship to existing issues

Suggested fix

The bridge should not inject any credentials into the sandbox. Instead:

  1. Register the inference provider via openshell provider create (already done during onboarding)
  2. The bridge invokes the agent via openshell sandbox connect or openshell sandbox exec — no credential arguments needed
  3. The agent uses inference.local for model calls, which routes through the gateway where credential injection happens server-side
  4. No NVIDIA_API_KEY export, no SSH command string with secrets, no write_auth_profile needed

The provider system is generic — it works for any credential, not just inference. No OpenShell changes are required to support this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions