Skip to content

CRITICAL: NVIDIA API Key Exposed in Process Arguments and Terminal Output #579

@ReterAI

Description

@ReterAI

Description

CRITICAL: NVIDIA API Key Exposed in Process Arguments and Terminal Output

Field Value
Severity Critical
CWE CWE-214 (Invocation of Process Using Visible Sensitive Information)
Files 6 files, 8+ locations
Status Active

Description

The NVIDIA_API_KEY is passed as a command-line argument to child processes in multiple scripts and JavaScript files. On Linux/macOS, command-line arguments are visible to any local user via ps aux or /proc/<pid>/cmdline. In one case, the raw key is also echoed to the terminal in cleartext.

This affects the production CLI tool, the setup scripts, the onboarding flow, and the E2E test harness.

Affected Locations

1. Key echoed to terminal in cleartext (WORST)

File: scripts/walkthrough.sh:72

echo "    export NVIDIA_API_KEY=$NVIDIA_API_KEY"

When tmux is not available, the script prints the full API key value to stdout as part of suggested commands. This value will appear in:

  • Terminal scrollback buffers
  • Terminal session recordings
  • CI/CD logs if run in automation
  • Screen sharing / screenshots

2. Key embedded in tmux command string

File: scripts/walkthrough.sh:88

tmux split-window -h -t "$SESSION" \
  "openshell sandbox connect nemoclaw -- bash -c 'export NVIDIA_API_KEY=$NVIDIA_API_KEY && nemoclaw-start openclaw agent --agent main --local --session-id live'"

The API key is embedded in the tmux command, visible via:

  • tmux list-windows -F '#{pane_start_command}'
  • ps aux during command startup

3. Key as openshell credential argument

File: scripts/setup.sh:122-126

upsert_provider \
  "nvidia-nim" \
  "openai" \
  "NVIDIA_API_KEY=$NVIDIA_API_KEY" \    # ← passed as CLI argument
  "OPENAI_BASE_URL=https://integrate.api.nvidia.com/v1"

The upsert_provider function passes credentials as arguments to openshell provider create --credential, making them visible in the process table.


4. Key as sandbox environment argument

File: scripts/setup.sh:182-184

openshell sandbox create --from "$BUILD_CTX/Dockerfile" --name "$SANDBOX_NAME" \
  --provider nvidia-nim \
  -- env NVIDIA_API_KEY="$NVIDIA_API_KEY" > "$CREATE_LOG" 2>&1

The key is passed as a CLI argument to openshell sandbox create. Note: the script is aware of this risk — line 189 filters the log output to avoid displaying it:

# Show progress lines (filter apt noise and env var dumps that contain NVIDIA_API_KEY)

5. Key in sudo command string

File: bin/nemoclaw.js:91

run(`sudo -E NVIDIA_API_KEY="${process.env.NVIDIA_API_KEY}" bash "${SCRIPTS}/setup-spark.sh"`);

The key is visible in the sudo command line. Both the parent process and the child bash process expose the key in /proc/*/cmdline.


6. Key as openshell provider credential (JavaScript)

File: bin/lib/onboard.js:729-734

run(
  `openshell provider create --name nvidia-nim --type openai ` +
  `--credential "NVIDIA_API_KEY=${process.env.NVIDIA_API_KEY}" ` +
  `--config "OPENAI_BASE_URL=https://integrate.api.nvidia.com/v1" 2>&1 || true`,
  { ignoreError: true }
);

Same issue as setup.sh — credential passed as CLI argument to openshell.


7. Key as sandbox env argument (JavaScript)

File: bin/lib/onboard.js:468-470

if (process.env.NVIDIA_API_KEY) {
  envArgs.push(`NVIDIA_API_KEY=${process.env.NVIDIA_API_KEY}`);
}

These envArgs are later passed as -- env KEY=VALUE CLI arguments to openshell sandbox create.


8. Key in curl Authorization header (test)

File: test/e2e/test-full-e2e.sh:229

-H "Authorization: Bearer $NVIDIA_API_KEY" \

The API key appears as a curl command-line argument, visible in the process table during the HTTP request.


9. Key in SSH command string (telegram bridge)

File: scripts/telegram-bridge.js:102

const cmd = `export NVIDIA_API_KEY='${API_KEY}' && nemoclaw-start openclaw agent --agent main --local -m '${escaped}' --session-id 'tg-${sessionId}'`;

The key is embedded in the SSH command string passed to spawn("ssh", [..., cmd]), visible in the process table. See separate report adv_shell_telegram_bridge.md for full analysis.


Impact

Any user on the same machine can harvest API keys by monitoring process arguments:

# Attacker's one-liner to harvest API keys from process arguments:
while true; do
  ps aux | grep -oP 'NVIDIA_API_KEY=\K[^ "]+' >> /tmp/harvested_keys.txt
  sleep 0.1
done

This is especially concerning in:

  • Shared development machines — multiple developers on the same box
  • CI/CD runners — shared runners process multiple tenants
  • Brev/cloud VMs — the deploy() function sends credentials to cloud instances

Recommended Fixes

For shell scripts (walkthrough.sh, setup.sh)

Echo fix (walkthrough.sh:72): Don't expand the variable — reference it instead:

# Before (leaks the key):
echo "    export NVIDIA_API_KEY=$NVIDIA_API_KEY"

# After (safe — tells user to use their existing env var):
echo "    export NVIDIA_API_KEY=\$NVIDIA_API_KEY"

Tmux fix (walkthrough.sh:88): Use tmux send-keys to type the export into the pane:

tmux split-window -h -t "$SESSION" "openshell sandbox connect nemoclaw"
tmux send-keys -t "$SESSION".1 "export NVIDIA_API_KEY=$NVIDIA_API_KEY && nemoclaw-start openclaw agent --agent main --local --session-id live" Enter

openshell credential fix (setup.sh, onboard.js): Check if openshell provider create supports --credential-stdin or --credential-file. If not, pass via environment variable:

# Before:
openshell provider create --credential "NVIDIA_API_KEY=$NVIDIA_API_KEY"

# After (if openshell supports env passthrough):
NVIDIA_API_KEY="$NVIDIA_API_KEY" openshell provider create --credential-env NVIDIA_API_KEY

For JavaScript (nemoclaw.js, onboard.js)

Use the env option of spawnSync/execSync:

// Before (key in CLI args):
run(`sudo -E NVIDIA_API_KEY="${process.env.NVIDIA_API_KEY}" bash "${SCRIPTS}/setup-spark.sh"`);

// After (key passed via process environment, not visible in ps):
run(`sudo -E bash "${SCRIPTS}/setup-spark.sh"`, {
  env: { ...process.env, NVIDIA_API_KEY: process.env.NVIDIA_API_KEY }
});

For curl (test-full-e2e.sh)

Use a netrc file or config file:

# Before:
curl -H "Authorization: Bearer $NVIDIA_API_KEY" ...

# After:
curl --config <(echo "-H \"Authorization: Bearer $NVIDIA_API_KEY\"") ...

Or use -H @- with stdin if supported by the curl version.

Risk Assessment

  • Impact: Credential theft by any local user on shared systems
  • Exploitability: Trivial — single ps aux | grep command
  • Blast radius: NVIDIA API key provides access to inference endpoints at integrate.api.nvidia.com and inference-api.nvidia.com, potentially incurring costs on the victim's account
  • Mitigating factors: On single-user developer machines, the only user who can read process args is the same user who owns the key. The risk is primarily on shared/CI systems.

Reproduction Steps

Environment

Debug Output

-

Logs

-

Checklist

  • I confirmed this bug is reproducible
  • I searched existing issues and this is not a duplicate

Metadata

Metadata

Assignees

No one assigned

    Labels

    Platform: MacOSSupport for MacOSbugSomething isn't workingpriority: highImportant issue that should be resolved in the next releasesecuritySomething isn't secure

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions