Skip to content

fix(security): replace process.env spread with allowlist in blueprint runner - #1874

Merged
ericksoa merged 7 commits into
mainfrom
fix/runner-env-allowlist
Apr 14, 2026
Merged

fix(security): replace process.env spread with allowlist in blueprint runner#1874
ericksoa merged 7 commits into
mainfrom
fix/runner-env-allowlist

Conversation

@ericksoa

@ericksoa ericksoa commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Introduce subprocess-env.ts — a shared module (mirrored in both CLI and plugin projects) that exports buildSubprocessEnv(). Defines an env var allowlist structured by category (system, temp, locale, proxy, TLS, toolchain) with prefix groups (LC_, XDG_, OPENSHELL_, GRPC_).
  • Apply the allowlist to two subprocess spawn sites:
    • nemoclaw/src/blueprint/runner.ts — provider create (the original bug target)
    • src/lib/services.ts — cloudflared spawn (same vulnerable { ...process.env } pattern)
  • src/lib/onboard.tsintentionally left on its existing blocklist to avoid regression risk on the highest-traffic code path. A TODO marks the future migration.
  • Static analysis guards in credential-exposure.test.ts now cover all three call sites, preventing ...process.env from creeping back into runner.ts or services.ts
  • Runtime regression test in runner.test.ts asserts secrets are stripped and proxy/openshell vars pass through

Test plan

  • make check — all hooks pass
  • npm test — all 1528 tests pass
  • New test: runner.test.ts "does not leak parent secrets into subprocess env"
  • New test: credential-exposure.test.ts guards for runner.ts and services.ts
  • Manual: verify nemoclaw apply configures inference provider correctly
  • Manual: verify behind a corporate proxy (HTTPS_PROXY passthrough)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Introduced allowlisted subprocess environment builder so spawned processes receive a filtered env plus explicit credentials.
  • Bug Fixes

    • Subprocess environment isolation: parent-process secrets are no longer forwarded; only explicit credentials and allowlisted system vars are passed.
  • Tests

    • Added regression checks to detect full-process env spreading and a test ensuring env filtering and test-env cleanup.
  • Documentation

    • Clarified destroy warning (includes persistent volume) and updated workspace file, persistence, backup, and "shell" usage guidance.

… runner

The runner's provider-create subprocess received the full parent
process.env, leaking secrets like NVIDIA_API_KEY, GITHUB_TOKEN, and
AWS_ACCESS_KEY_ID to child processes. Replace the { ...process.env }
spread with buildSubprocessEnv(), which forwards only an explicit
allowlist of system variables (PATH, HOME, LANG, etc.) and injects
credentials through the existing credEnv overlay.

Adds runtime regression test (runner.test.ts) and static analysis
guard (credential-exposure.test.ts) to prevent reintroduction.

Closes NVBug 6010004

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replace full inheritance of host process.env for spawned subprocesses with a filtered allowlist via buildSubprocessEnv(...); update runner and service spawn calls to use it, add tests preventing env-spread patterns, and adjust onboarding comments and docs and workspace docs.

Changes

Cohort / File(s) Summary
Subprocess env module
nemoclaw/src/lib/subprocess-env.ts, src/lib/subprocess-env.ts
Add buildSubprocessEnv(extra?): allowlist-based env builder (explicit names + prefixes) that returns a filtered env merged with optional extra.
Runner updates & test
nemoclaw/src/blueprint/runner.ts, nemoclaw/src/blueprint/runner.test.ts
Use buildSubprocessEnv(credEnv) for provider subprocess env; add test asserting explicit creds passed, parent secrets omitted, allowlisted vars/proxy/debug pass-through, and restore process.env.
Service spawn updates
src/lib/services.ts
Change spawn child env to buildSubprocessEnv(env) instead of { ...process.env, ...env }.
Sandbox onboarding note
src/lib/onboard.ts
Add TODO comment about migrating sandbox create blocklist to shared allowlist; existing sandbox env blocklist remains unchanged.
Credential-regression tests
test/credential-exposure.test.ts
Add regression assertions that read source files and fail on env: { ...process.env }-style spreads; update sandbox-secret assertion comments.
Docs / user workspace & commands
.agents/skills/nemoclaw-user-reference/references/commands.md, .agents/skills/nemoclaw-user-workspace/SKILL.md, .agents/skills/nemoclaw-user-workspace/references/workspace-files.md
Clarify destroy deletes sandbox + persistent volume; simplify workspace-file descriptions; change examples from connectshell; update backup/persistence guidance and remove outdated sections.

Sequence Diagram(s)

sequenceDiagram
  participant Parent as Parent Process\n(process.env)
  participant Runner as Runner / Onboard / Services
  participant Builder as buildSubprocessEnv\n(allowlist)
  participant Subproc as Subprocess\n(execa / spawn)

  Parent->>Runner: invoke action/start/create
  Runner->>Builder: buildSubprocessEnv(optional extra)
  Builder->>Builder: filter process.env by allowed names/prefixes
  Runner->>Builder: provide explicit credential overlay (extra)
  Builder-->>Runner: return filteredEnv + extra
  Runner->>Subproc: spawn subprocess with env = filteredEnv+extra
  Subproc-->>Runner: subprocess starts (no parent secrets)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped through envs with careful paws,
Hid secret keys behind polite laws,
Let PATH and HOME slip through the gate,
Creds supplied plainly—no accidental state,
Subprocesses safe; I munch my carrots.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: replacing unsafe process.env spreads with an allowlist mechanism in the blueprint runner, which is the core security fix in this PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runner-env-allowlist

Comment @coderabbitai help to get the list of available commands and usage tips.

@ericksoa ericksoa self-assigned this Apr 14, 2026
ericksoa and others added 2 commits April 14, 2026 07:24
…list

Extend the env allowlist to include variables needed in corporate
environments: HTTP(S)_PROXY, NO_PROXY, SSL_CERT_*, NODE_EXTRA_CA_CERTS,
DOCKER_HOST, KUBECONFIG, SSH_AUTH_SOCK, RUST_LOG/BACKTRACE, and
OPENSHELL_*/GRPC_* prefixes. Without these the subprocess would silently
fail behind proxies or with custom CA bundles.

Adds test assertions for HTTPS_PROXY and OPENSHELL_* passthrough.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@nemoclaw/src/blueprint/runner.test.ts`:
- Around line 433-464: The finally block in the test "does not leak parent
secrets into subprocess env (NVBug 6010004)" unconditionally deletes process.env
keys (MY_API_KEY, GITHUB_TOKEN, AWS_ACCESS_KEY_ID, NVIDIA_API_KEY), which can
erase pre-existing values and pollute other tests; modify the test to capture
the original values before setting them (e.g., save originalMyApiKey =
process.env.MY_API_KEY, etc.), then in the finally restore each env var to its
original value (setting it back if defined, or deleting it only if it was
originally undefined), keeping the rest of the test logic (actionApply,
mockExeca lookup) unchanged so that cleanup safely restores prior state.

In `@test/credential-exposure.test.ts`:
- Around line 42-52: The test currently only scans per-line so a spread of
process.env across multiple lines can evade the check; update the check in
credential-exposure.test.ts to scan the full RUNNER_TS source with a
multiline-capable regex (update spreadRe to use [\s\S]* or the /s flag, e.g.
/env:\s*\{[\s\S]*\.\.\.process\.env/) and run it against the entire src string
instead of line-by-line, and also ensure you ignore matches inside comments by
stripping or ignoring both // and /* */ comments before testing; keep the
expectation that runner.ts must use buildSubprocessEnv() and assert no
violations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3ce6ac14-7a36-4a6e-81e5-aec5698008dd

📥 Commits

Reviewing files that changed from the base of the PR and between 9f67b2c and d3667d2.

📒 Files selected for processing (3)
  • nemoclaw/src/blueprint/runner.test.ts
  • nemoclaw/src/blueprint/runner.ts
  • test/credential-exposure.test.ts

Comment thread nemoclaw/src/blueprint/runner.test.ts Outdated
Comment thread test/credential-exposure.test.ts Outdated
Move the env var allowlist out of runner.ts into a dedicated shared
module (subprocess-env.ts) mirrored in both the CLI and plugin
projects. Apply it to all three subprocess spawn sites:

- nemoclaw/src/blueprint/runner.ts (provider create)
- src/lib/services.ts (cloudflared spawn)
- src/lib/onboard.ts (sandbox create — replaces the old blocklist)

The allowlist is structured by category (system, temp, locale, proxy,
TLS, toolchain) with named prefix groups (LC_, XDG_, OPENSHELL_,
GRPC_). The old hand-rolled blocklist in onboard.ts is removed —
the allowlist approach is strictly more secure because it rejects
unknown/future secrets by default.

Static analysis guards in credential-exposure.test.ts now cover all
three call sites.

Closes NVBug 6010004

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
.agents/skills/nemoclaw-user-workspace/references/workspace-files.md (1)

50-50: Tighten duplicated phrasing in the warning reference.

Line 50 currently repeats “See … (see …)”. Consider simplifying to one reference to avoid awkward wording.

✍️ Suggested wording
-> See Backup and Restore (see the `nemoclaw-user-workspace` skill) for instructions.
+> See **Backup and Restore** in the `nemoclaw-user-workspace` skill for instructions.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/nemoclaw-user-workspace/references/workspace-files.md at line
50, The phrase "See Backup and Restore (see the `nemoclaw-user-workspace` skill)
for instructions." repeats "see"; update the sentence in workspace-files.md to
remove the duplication—e.g., "See Backup and Restore in the
`nemoclaw-user-workspace` skill for instructions." Edit the line containing that
sentence so it references the `nemoclaw-user-workspace` skill once and retains
the same meaning.
nemoclaw/src/lib/subprocess-env.ts (1)

17-18: Prevent mirror drift for this security-critical helper.

Since this file is intentionally mirrored in another project, add a parity guard (test or generation step) so allowlist changes cannot diverge silently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nemoclaw/src/lib/subprocess-env.ts` around lines 17 - 18, Add an automated
parity guard to prevent the mirrored src/lib/subprocess-env.ts from drifting:
implement a unit/integration test (or CI generation check) that loads this file
and its counterpart in the CLI repo, normalizes whitespace/comments, and asserts
their contents (or computed checksum) are identical; name the test something
like "subprocess-env parity" and fail the build/CI if the files differ so
allowlist changes cannot diverge silently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.agents/skills/nemoclaw-user-workspace/SKILL.md:
- Line 3: Fix the frontmatter "description" field in SKILL.md by correcting
typos and improving grammar: replace "Hows" with "How to" and "Whats" with
"What", and rephrase the sentence to read like a single clear clause (for
example: "How to back up and restore OpenClaw workspace files before destructive
operations, what workspace personality and configuration files are, where they
live, and how they persist across sandbox restarts."); update the description
value in the SKILL.md frontmatter accordingly and regenerate the auto-generated
skill file so the docs output matches this corrected text.
- Around line 56-57: Update the warning text for the "nemoclaw <name> destroy"
command to be less absolute about PVC deletion: replace the phrase that says it
"deletes the sandbox and its PVC" with wording that reflects the implementation
path ("deletes the sandbox") and that sandbox deletion may remove associated
workspace storage (e.g., PVCs) and that files can be permanently lost unless
backed up; reference the command name "nemoclaw <name> destroy" and the concept
"sandbox delete" when making the change.

---

Nitpick comments:
In @.agents/skills/nemoclaw-user-workspace/references/workspace-files.md:
- Line 50: The phrase "See Backup and Restore (see the `nemoclaw-user-workspace`
skill) for instructions." repeats "see"; update the sentence in
workspace-files.md to remove the duplication—e.g., "See Backup and Restore in
the `nemoclaw-user-workspace` skill for instructions." Edit the line containing
that sentence so it references the `nemoclaw-user-workspace` skill once and
retains the same meaning.

In `@nemoclaw/src/lib/subprocess-env.ts`:
- Around line 17-18: Add an automated parity guard to prevent the mirrored
src/lib/subprocess-env.ts from drifting: implement a unit/integration test (or
CI generation check) that loads this file and its counterpart in the CLI repo,
normalizes whitespace/comments, and asserts their contents (or computed
checksum) are identical; name the test something like "subprocess-env parity"
and fail the build/CI if the files differ so allowlist changes cannot diverge
silently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 089fbc98-0abb-40ae-bc0f-890a6e72ed36

📥 Commits

Reviewing files that changed from the base of the PR and between a87f5f4 and be20f26.

📒 Files selected for processing (9)
  • .agents/skills/nemoclaw-user-reference/references/commands.md
  • .agents/skills/nemoclaw-user-workspace/SKILL.md
  • .agents/skills/nemoclaw-user-workspace/references/workspace-files.md
  • nemoclaw/src/blueprint/runner.ts
  • nemoclaw/src/lib/subprocess-env.ts
  • src/lib/onboard.ts
  • src/lib/services.ts
  • src/lib/subprocess-env.ts
  • test/credential-exposure.test.ts
✅ Files skipped from review due to trivial changes (1)
  • .agents/skills/nemoclaw-user-reference/references/commands.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • nemoclaw/src/blueprint/runner.ts
  • test/credential-exposure.test.ts

---
name: "nemoclaw-user-workspace"
description: "Backs up and restores OpenClaw workspace files before destructive operations. Use when backing up a sandbox, restoring workspace state, or preparing for a destructive operation. Explains what workspace files are, where they live, and how they persist across sandbox restarts. Use when asking about soul.md, identity.md, memory.md, agents.md, or sandbox file persistence."
description: "Hows to back up and restore OpenClaw workspace files before destructive operations. Whats workspace personality and configuration files are, where they live, and how they persist across sandbox restarts."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix grammar in frontmatter description.

Line 3 has typos (“Hows”, “Whats”) and reads ungrammatically. This is user-facing metadata and should be corrected in the docs source, then regenerated into this skill file.

✍️ Suggested text
-description: "Hows to back up and restore OpenClaw workspace files before destructive operations. Whats workspace personality and configuration files are, where they live, and how they persist across sandbox restarts."
+description: "How to back up and restore OpenClaw workspace files before destructive operations, and what workspace personality/configuration files are, where they live, and how they persist across sandbox restarts."
Based on learnings: "In NVIDIA/NemoClaw, treat `.agents/skills/nemoclaw-user-*/*.md` (SKILL.md) files as auto-generated... do not flag these as manual edit violations. Only flag ... when the PR does NOT include corresponding changes ... under `docs/`."
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
description: "Hows to back up and restore OpenClaw workspace files before destructive operations. Whats workspace personality and configuration files are, where they live, and how they persist across sandbox restarts."
description: "How to back up and restore OpenClaw workspace files before destructive operations, and what workspace personality/configuration files are, where they live, and how they persist across sandbox restarts."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/nemoclaw-user-workspace/SKILL.md at line 3, Fix the
frontmatter "description" field in SKILL.md by correcting typos and improving
grammar: replace "Hows" with "How to" and "Whats" with "What", and rephrase the
sentence to read like a single clear clause (for example: "How to back up and
restore OpenClaw workspace files before destructive operations, what workspace
personality and configuration files are, where they live, and how they persist
across sandbox restarts."); update the description value in the SKILL.md
frontmatter accordingly and regenerate the auto-generated skill file so the docs
output matches this corrected text.

Comment on lines +56 to +57
Running `nemoclaw <name> destroy` **deletes the sandbox and its PVC**.
All workspace files are permanently lost unless you back them up first.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make destroy/PVC wording slightly less absolute.

Line 56 currently asserts direct PVC deletion. The implementation path uses sandbox delete, with storage cleanup as behavior of that operation; consider wording this as associated workspace storage removal for long-term accuracy.

✍️ Suggested wording
-Running `nemoclaw <name> destroy` **deletes the sandbox and its PVC**.
+Running `nemoclaw <name> destroy` **deletes the sandbox and its associated workspace storage**.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Running `nemoclaw <name> destroy` **deletes the sandbox and its PVC**.
All workspace files are permanently lost unless you back them up first.
Running `nemoclaw <name> destroy` **deletes the sandbox and its associated workspace storage**.
All workspace files are permanently lost unless you back them up first.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/nemoclaw-user-workspace/SKILL.md around lines 56 - 57, Update
the warning text for the "nemoclaw <name> destroy" command to be less absolute
about PVC deletion: replace the phrase that says it "deletes the sandbox and its
PVC" with wording that reflects the implementation path ("deletes the sandbox")
and that sandbox deletion may remove associated workspace storage (e.g., PVCs)
and that files can be permanently lost unless backed up; reference the command
name "nemoclaw <name> destroy" and the concept "sandbox delete" when making the
change.

Keep onboard.ts on its battle-tested blocklist to avoid regression
risk on the highest-traffic code path. The allowlist is applied only
to runner.ts and services.ts where the blast radius is smaller.

Also removes all internal bug tracker references from source code
comments — those belong in commit messages, not in a public repo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
nemoclaw/src/lib/subprocess-env.ts (1)

17-18: Reduce mirror-drift risk for security-critical logic.

The “keep them in sync” comment is helpful, but manual sync can drift over time. Consider a shared source module (or parity test) so CLI/plugin allowlists can’t silently diverge.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nemoclaw/src/lib/subprocess-env.ts` around lines 17 - 18, The comment warns
that src/lib/subprocess-env.ts is a mirrored copy and can drift; replace the
duplicated logic by extracting the security-critical allowlist logic into a
single shared module (e.g., export functions/constants from a new shared
package/module used by both subprocess-env.ts and the CLI counterpart) or add an
automated parity test that imports both subprocess-env.ts and the CLI mirror to
assert equality of exported allowlists/constants; update references in
subprocess-env.ts to re-export or import from the shared module and add the
parity test to CI to prevent silent divergence.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@nemoclaw/src/lib/subprocess-env.ts`:
- Around line 17-18: The comment warns that src/lib/subprocess-env.ts is a
mirrored copy and can drift; replace the duplicated logic by extracting the
security-critical allowlist logic into a single shared module (e.g., export
functions/constants from a new shared package/module used by both
subprocess-env.ts and the CLI counterpart) or add an automated parity test that
imports both subprocess-env.ts and the CLI mirror to assert equality of exported
allowlists/constants; update references in subprocess-env.ts to re-export or
import from the shared module and add the parity test to CI to prevent silent
divergence.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c2b104f-c816-42ca-ae68-9960bba52f7d

📥 Commits

Reviewing files that changed from the base of the PR and between be20f26 and a5e9a7b.

📒 Files selected for processing (5)
  • nemoclaw/src/blueprint/runner.test.ts
  • nemoclaw/src/lib/subprocess-env.ts
  • src/lib/onboard.ts
  • src/lib/subprocess-env.ts
  • test/credential-exposure.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/lib/onboard.ts
  • nemoclaw/src/blueprint/runner.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/credential-exposure.test.ts
  • src/lib/subprocess-env.ts

ericksoa and others added 2 commits April 14, 2026 07:55
- Preserve original env var values in test cleanup instead of
  unconditionally deleting (prevents test pollution)
- Use multiline-capable regex for static process.env spread detection
  so the guard cannot be evaded by splitting across lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything to make onboard.ts smaller!

@ericksoa
ericksoa merged commit c527171 into main Apr 14, 2026
9 checks passed
@cv cv added the v0.0.16 label Apr 14, 2026
ColinM-sys pushed a commit to ColinM-sys/NemoClaw that referenced this pull request Apr 14, 2026
… runner (NVIDIA#1874)

## Summary

- Introduce `subprocess-env.ts` — a shared module (mirrored in both CLI
and plugin projects) that exports `buildSubprocessEnv()`. Defines an env
var allowlist structured by category (system, temp, locale, proxy, TLS,
toolchain) with prefix groups (LC_, XDG_, OPENSHELL_, GRPC_).
- Apply the allowlist to two subprocess spawn sites:
- `nemoclaw/src/blueprint/runner.ts` — provider create (the original bug
target)
- `src/lib/services.ts` — cloudflared spawn (same vulnerable `{
...process.env }` pattern)
- `src/lib/onboard.ts` — **intentionally left on its existing
blocklist** to avoid regression risk on the highest-traffic code path. A
TODO marks the future migration.
- Static analysis guards in `credential-exposure.test.ts` now cover all
three call sites, preventing `...process.env` from creeping back into
runner.ts or services.ts
- Runtime regression test in `runner.test.ts` asserts secrets are
stripped and proxy/openshell vars pass through

## Test plan

- [x] `make check` — all hooks pass
- [x] `npm test` — all 1528 tests pass
- [x] New test: `runner.test.ts` "does not leak parent secrets into
subprocess env"
- [x] New test: `credential-exposure.test.ts` guards for runner.ts and
services.ts
- [ ] Manual: verify `nemoclaw apply` configures inference provider
correctly
- [ ] Manual: verify behind a corporate proxy (HTTPS_PROXY passthrough)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Introduced allowlisted subprocess environment builder so spawned
processes receive a filtered env plus explicit credentials.

* **Bug Fixes**
* Subprocess environment isolation: parent-process secrets are no longer
forwarded; only explicit credentials and allowlisted system vars are
passed.

* **Tests**
* Added regression checks to detect full-process env spreading and a
test ensuring env filtering and test-env cleanup.

* **Documentation**
* Clarified destroy warning (includes persistent volume) and updated
workspace file, persistence, backup, and "shell" usage guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: ColinM-sys <cmcdonough@50words.com>
ColinM-sys added a commit to ColinM-sys/NemoClaw that referenced this pull request Apr 14, 2026
The sandbox creation path passed the host's entire process.env into
the sandbox, filtered only by a 12-entry blocklist. Every env var
NOT in that list leaked into the sandbox where the AI agent runs
with code execution — including GITHUB_TOKEN, AWS_SECRET_ACCESS_KEY,
SSH_AUTH_SOCK, KUBECONFIG, NPM_TOKEN, and any CI/CD secrets.

Switch to the shared subprocess-env.ts allowlist (introduced in
PR NVIDIA#1874) which inverts the default: only known-safe variables
(HOME, PATH, TERM, locale, proxy, TLS) are forwarded. Everything
else is dropped.

Additionally strip KUBECONFIG and SSH_AUTH_SOCK from the sandbox-
specific environment — the generic allowlist includes these for
host-side processes but the sandbox should never have access to the
host's Kubernetes cluster or SSH agent.

This was flagged as a TODO at the original site (lines 2702-2705)
but left unapplied to the sandbox create path, which is the
highest-impact code path because it runs the AI agent.

Signed-off-by: ColinM-sys <cmcdonough@50words.com>
cv pushed a commit that referenced this pull request Apr 16, 2026
#1893)

## Summary
- Replace the 12-entry env var blocklist in the sandbox creation path
with the shared `subprocess-env.ts` allowlist. The blocklist passed the
host's entire `process.env` into the sandbox minus only 12 specific
names. The allowlist inverts the default: only known-safe variables are
forwarded.
- Additionally strip `KUBECONFIG` and `SSH_AUTH_SOCK` from the sandbox
environment — the generic allowlist includes these for host-side
processes but the sandbox should never have access to the host's
Kubernetes cluster or SSH agent.

## Why
The sandbox runs an AI agent with code execution. The blocklist only
blocked 12 credential names and leaked **everything else** into the
sandbox, including:

- `GITHUB_TOKEN` (confirmed absent from blocklist)
- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`
- `SSH_AUTH_SOCK` (host SSH agent access)
- `KUBECONFIG` (host Kubernetes cluster access)
- `NPM_TOKEN`, `DOCKER_PASSWORD`
- `DATABASE_URL`, `REDIS_URL`, `MONGO_URI`
- Any CI/CD secrets (`GITLAB_TOKEN`, `CIRCLECI_TOKEN`, etc.)

A prompt-injected or compromised agent could read these via
`process.env` and exfiltrate them through any allowed egress channel.

The correct fix — `subprocess-env.ts` — already exists in the codebase
(PR #1874) and is applied to `blueprint/runner.ts` and `services.ts`.
The sandbox creation path was explicitly left on the old blocklist with
a TODO comment (lines 2702-2705). This PR completes that migration for
the highest-impact code path.

## What changed
- `src/lib/onboard.ts` — import `buildSubprocessEnv` from
`subprocess-env.ts`, replace the blocklist + `process.env` filter with
`buildSubprocessEnv()`, delete `KUBECONFIG` and `SSH_AUTH_SOCK` from the
result.

## Test plan
- [x] `npm run build:cli` — compiles cleanly.
- [ ] Manual: `nemoclaw onboard` with Ollama — verify sandbox can still
reach inference (the allowlist includes `HOME`, `PATH`, `TERM`, proxy
vars, and TLS vars which are sufficient).
- [ ] Manual: set `GITHUB_TOKEN=test123` in host env, onboard, exec into
sandbox, verify `echo $GITHUB_TOKEN` is empty.

Signed-off-by: ColinM-sys <cmcdonough@50words.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved sandbox environment isolation so host-level access
credentials are no longer forwarded into sandboxes; KUBECONFIG and
SSH_AUTH_SOCK are explicitly excluded.
* Replaced legacy blocklist handling with a consistent allowlist-based
environment snapshot for more predictable and secure sandbox startups.

* **Tests**
* Updated regression tests to verify the allowlist-based environment
behavior and explicit exclusion of host credential variables.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: ColinM-sys <cmcdonough@50words.com>
Signed-off-by: Test User <test@example.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Co-authored-by: Aaron Erickson <aerickson@nvidia.com>
cv pushed a commit that referenced this pull request Apr 29, 2026
#2616) (#2662)

## Summary

On hosts with a system HTTP proxy (Privoxy, corporate CONNECT proxy,
Cursor's bundled proxy), NemoClaw spawned the Ollama daemon and its
`:11435` auth proxy with `HTTP_PROXY` inherited from the shell but no
`NO_PROXY` set. Loopback requests — the auth-proxy health probe, `ollama
pull`, and macOS curl's token validation — were tunnelled through the
proxy and failed with:

```
HTTP 500 — Internal Privoxy Error
Privoxy could not connect to the host: 127.0.0.1:11435
```

The root cause is two call sites that used `{ ...process.env }` directly
instead of the shared `buildSubprocessEnv()` allowlist, combined with
`buildSubprocessEnv()` not guarding against a proxy-without-NO_PROXY
environment.

## Related Issue

Fixes #2616

## How the fix works

| Call site | Before | After |
|---|---|---|
| `spawnOllamaAuthProxy()` | `{ ...process.env, token, ports }` — full
env including secrets | `buildSubprocessEnv({ token, ports })` —
allowlisted env + NO_PROXY injected |
| `pullOllamaModel()` | `{ ...process.env }` — full env |
`buildSubprocessEnv()` — allowlisted env + NO_PROXY injected |
| `buildSubprocessEnv()` | forwards `HTTP_PROXY` with no `NO_PROXY`
guard | calls `withLocalNoProxy()` which appends `localhost,127.0.0.1`
to both `NO_PROXY` and `no_proxy` when any proxy var is present |

`withLocalNoProxy()` is additive: it appends only the missing entries so
an existing `NO_PROXY=corp.internal` becomes
`corp.internal,localhost,127.0.0.1`, preserving outbound proxy
functionality for external registries like `registry.ollama.ai`.

## Changes

- **`src/lib/subprocess-env.ts`**: add exported `withLocalNoProxy(env)`
helper; call it at the end of `buildSubprocessEnv()`. When `HTTP_PROXY`,
`HTTPS_PROXY`, `http_proxy`, or `https_proxy` is present, appends
`localhost` and `127.0.0.1` to both `NO_PROXY` and `no_proxy` if either
entry is missing.
- **`nemoclaw/src/lib/subprocess-env.ts`**: mirror of above (kept in
sync per existing policy).
- **`src/lib/onboard-ollama-proxy.ts`**: add
`require("./subprocess-env")` import; switch `spawnOllamaAuthProxy()`
from `{ ...process.env, ... }` to `buildSubprocessEnv({ ... })` (also
fixes the #1874 secret-leakage risk for this spawn); switch
`pullOllamaModel()` from `{ ...process.env }` to `buildSubprocessEnv()`.
- **`src/lib/subprocess-env.test.ts`** (new): 11 unit tests covering
`withLocalNoProxy` (no proxy → no-op, HTTP_PROXY/HTTPS_PROXY/http_proxy
each trigger injection, partial NO_PROXY is extended, full NO_PROXY is
unchanged) and `buildSubprocessEnv` integration (injection on proxy set,
augmentation of existing NO_PROXY, no injection when no proxy, extra
vars preserved).

## Type of Change

- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Verification

- [ ] `npx prek run --all-files` passes
- [x] `npm test` passes (subprocess-env: 11/11 new tests pass; full
suite clean)
- [x] Tests added or updated for new or changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Docs updated for user-facing behavior changes
- [ ] `make docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

## AI Disclosure

- [x] AI-assisted — tool: Claude Code

---
Signed-off-by: Dongni Yang <dongniy@nvidia.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed HTTP proxy configuration to ensure localhost and loopback
traffic properly bypass proxy routing when proxy environment variables
are configured.

* **Tests**
* Added comprehensive test coverage for proxy bypass functionality in
subprocess environment setup.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Dongni Yang <dongniy@nvidia.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
DemianHeyGen pushed a commit to DemianHeyGen/NemoClaw that referenced this pull request Apr 30, 2026
NVIDIA#2616) (NVIDIA#2662)

## Summary

On hosts with a system HTTP proxy (Privoxy, corporate CONNECT proxy,
Cursor's bundled proxy), NemoClaw spawned the Ollama daemon and its
`:11435` auth proxy with `HTTP_PROXY` inherited from the shell but no
`NO_PROXY` set. Loopback requests — the auth-proxy health probe, `ollama
pull`, and macOS curl's token validation — were tunnelled through the
proxy and failed with:

```
HTTP 500 — Internal Privoxy Error
Privoxy could not connect to the host: 127.0.0.1:11435
```

The root cause is two call sites that used `{ ...process.env }` directly
instead of the shared `buildSubprocessEnv()` allowlist, combined with
`buildSubprocessEnv()` not guarding against a proxy-without-NO_PROXY
environment.

## Related Issue

Fixes NVIDIA#2616

## How the fix works

| Call site | Before | After |
|---|---|---|
| `spawnOllamaAuthProxy()` | `{ ...process.env, token, ports }` — full
env including secrets | `buildSubprocessEnv({ token, ports })` —
allowlisted env + NO_PROXY injected |
| `pullOllamaModel()` | `{ ...process.env }` — full env |
`buildSubprocessEnv()` — allowlisted env + NO_PROXY injected |
| `buildSubprocessEnv()` | forwards `HTTP_PROXY` with no `NO_PROXY`
guard | calls `withLocalNoProxy()` which appends `localhost,127.0.0.1`
to both `NO_PROXY` and `no_proxy` when any proxy var is present |

`withLocalNoProxy()` is additive: it appends only the missing entries so
an existing `NO_PROXY=corp.internal` becomes
`corp.internal,localhost,127.0.0.1`, preserving outbound proxy
functionality for external registries like `registry.ollama.ai`.

## Changes

- **`src/lib/subprocess-env.ts`**: add exported `withLocalNoProxy(env)`
helper; call it at the end of `buildSubprocessEnv()`. When `HTTP_PROXY`,
`HTTPS_PROXY`, `http_proxy`, or `https_proxy` is present, appends
`localhost` and `127.0.0.1` to both `NO_PROXY` and `no_proxy` if either
entry is missing.
- **`nemoclaw/src/lib/subprocess-env.ts`**: mirror of above (kept in
sync per existing policy).
- **`src/lib/onboard-ollama-proxy.ts`**: add
`require("./subprocess-env")` import; switch `spawnOllamaAuthProxy()`
from `{ ...process.env, ... }` to `buildSubprocessEnv({ ... })` (also
fixes the NVIDIA#1874 secret-leakage risk for this spawn); switch
`pullOllamaModel()` from `{ ...process.env }` to `buildSubprocessEnv()`.
- **`src/lib/subprocess-env.test.ts`** (new): 11 unit tests covering
`withLocalNoProxy` (no proxy → no-op, HTTP_PROXY/HTTPS_PROXY/http_proxy
each trigger injection, partial NO_PROXY is extended, full NO_PROXY is
unchanged) and `buildSubprocessEnv` integration (injection on proxy set,
augmentation of existing NO_PROXY, no injection when no proxy, extra
vars preserved).

## Type of Change

- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Verification

- [ ] `npx prek run --all-files` passes
- [x] `npm test` passes (subprocess-env: 11/11 new tests pass; full
suite clean)
- [x] Tests added or updated for new or changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Docs updated for user-facing behavior changes
- [ ] `make docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

## AI Disclosure

- [x] AI-assisted — tool: Claude Code

---
Signed-off-by: Dongni Yang <dongniy@nvidia.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed HTTP proxy configuration to ensure localhost and loopback
traffic properly bypass proxy routing when proxy environment variables
are configured.

* **Tests**
* Added comprehensive test coverage for proxy bypass functionality in
subprocess environment setup.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Dongni Yang <dongniy@nvidia.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
tantodefi added a commit to tantodefi/NemoClaw that referenced this pull request May 14, 2026
Merge upstream/main into tantodefi/NemoClaw fork. Key upstream additions:
- TypeScript migration of bin/lib/ -> src/lib/ (all CLI code now TS)
- buildSubprocessEnv() security refactor (strips secrets from subprocess env)
- Hermes agent (agents/hermes/), OpenClaw agent manifest
- Policy tiers (nemoclaw-blueprint/policies/tiers.yaml)
- Shields/audit, secret scanner, sandbox-session-state
- New e2e test suites (ollama, hermes, network policy, shields)
- Windows/WSL e2e support

Downstream changes preserved:
- GITHUB_TOKEN, PROTON_USERNAME, PROTON_PASSWORD explicit sandbox injection
  (via buildSubprocessEnv() extra param pattern from NVIDIA#1874)
- gbrain.yaml policy preset and GitHub workflow stubs (untracked, popping stash next)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@wscurran wscurran added the bug-fix PR fixes a bug or regression label Jun 8, 2026
@cv
cv deleted the fix/runner-env-allowlist branch June 28, 2026 00:21
yimoj added a commit that referenced this pull request Jul 3, 2026
The prebuild ran the local `docker build` under the shared subprocess
allowlist minus KUBECONFIG/SSH_AUTH_SOCK. That allowlist already
default-denies host secrets (NVIDIA_INFERENCE_API_KEY, GITHUB_TOKEN, AWS_*
per #1874), but it still forwarded OPENSHELL_*/GRPC_* control-plane env and
RUST_* debug knobs that a `docker build` never consumes.

Add dockerBuildSubprocessEnv() to forward only the Docker-build boundary —
system, Docker daemon (DOCKER_HOST + the XDG_* the docker CLI reads for its
config/credential store), proxy, locale, temp, and TLS CA — and drop the
broader host/control-plane vars (resolves PR Review Advisor least-privilege
finding on sandbox-prebuild.ts). Subtractive of provably-unused vars, so no
behaviour change to the build; covered by a new allowlist unit test.

Signed-off-by: Yimo Jiang <yimoj@nvidia.com>

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants