Skip to content

fix(security): disable remote uninstall execution fallback#1476

Open
Saibabu7770 wants to merge 7 commits intoNVIDIA:mainfrom
Saibabu7770:fix/uninstall-fallback-no-curl-pipe-577
Open

fix(security): disable remote uninstall execution fallback#1476
Saibabu7770 wants to merge 7 commits intoNVIDIA:mainfrom
Saibabu7770:fix/uninstall-fallback-no-curl-pipe-577

Conversation

@Saibabu7770
Copy link
Copy Markdown

@Saibabu7770 Saibabu7770 commented Apr 4, 2026

Stop executing downloaded uninstall scripts when local uninstall.sh is missing. Require manual review/download instead and add a regression guard to prevent reintroducing remote execution fallback.

Summary

Related Issue

Changes

Type of Change

  • Code change for a new feature, bug fix, or refactor.
  • Code change with doc updates.
  • Doc only. Prose changes without code sample modifications.
  • Doc only. Includes code sample changes.

Testing

  • npx prek run --all-files passes (or equivalently make check).
  • npm test passes.
  • make docs builds without warnings. (for doc-only changes)

Checklist

General

Code Changes

  • Formatters applied — npx prek run --all-files auto-fixes formatting (or make format for targeted runs).
  • Tests added or updated for new or changed behavior.
  • No secrets, API keys, or credentials committed.
  • Doc pages updated for any user-facing behavior changes (new commands, changed defaults, new features, bug fixes that contradict existing docs).

Doc Changes

  • Follows the style guide. Try running the update-docs agent skill to draft changes while complying with the style guide. For example, prompt your agent with "/update-docs catch up the docs for the new changes I made in this PR."
  • New pages include SPDX license header and frontmatter, if creating a new page.
  • Cross-references and links verified.

Signed-off-by: Your Name your-email@example.com

Summary by CodeRabbit

  • Bug Fixes
    • Removed automatic remote script fallback from the uninstall command for enhanced security. When the local uninstall script is unavailable, the command now exits with an error message providing the download URL, requiring users to manually review and execute the script.

Stop executing downloaded uninstall scripts when local uninstall.sh is missing. Require manual review/download instead and add a regression guard to prevent reintroducing remote execution fallback.

Made-with: Cursor
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b41f49d2-6798-4a89-b9ed-ee4f5972984e

📥 Commits

Reviewing files that changed from the base of the PR and between 8426ed6 and 5e0bb16.

📒 Files selected for processing (4)
  • src/lib/uninstall-command.test.ts
  • src/lib/uninstall-command.ts
  • src/nemoclaw.ts
  • test/runner.test.ts
✅ Files skipped from review due to trivial changes (1)
  • src/nemoclaw.ts

📝 Walkthrough

Walkthrough

The PR removes remote uninstall script fallback functionality for security reasons. When no local uninstall script exists, the command now returns an error message with the script URL and instructions for manual download/review, exiting with status 1, instead of automatically downloading and executing a remote script via curl.

Changes

Cohort / File(s) Summary
Core uninstall logic
src/lib/uninstall-command.ts
Removed remote fallback path that created temp directories, downloaded scripts via curl, and executed them with bash. Now logs error messages and exits with status 1 when no local script is found.
Test suite updates
src/lib/uninstall-command.test.ts, test/runner.test.ts
Updated uninstall command test to reflect new error-exit behavior; removed expectations for temp file operations and remote downloads. Added regression-guard test that asserts curl/bash remote execution patterns are absent and security-disabled message is present.
Help text
src/nemoclaw.ts
Updated uninstall command help output to describe behavior as "local only; no remote fallback" instead of prior "local first, curl fallback" description.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 No more scripts from afar, we hop with care,
Local paths only—safety in the air,
Remove that curl, that bash so swift,
Manual review now—a cautious gift!
Security hardened, the warren's delight. 🔒

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.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 security-focused change: disabling the remote uninstall execution fallback. It is concise, specific, and clearly summarizes the primary change in the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@test/runner.test.js`:
- Around line 666-670: The test's regression guard in uninstallBlock (extracted
from "function uninstall(args)") is too narrow: update the assertions to detect
any remote execution fallback, not just the literal spawnSync("bash",
[uninstallScript...]) form. Replace the second not.toMatch with a broader regex
against uninstallBlock that matches spawnSync("bash", ...) when the argument
array contains uninstallScript (for example
/spawnSync\(\s*["']bash["']\s*,\s*\[[^\]]*uninstallScript[^\]]*\]/) and keep the
existing execFileSync("curl") check (or broaden it to
/exec(File)?Sync\(\s*["']curl["']/) so any variant that invokes curl/remote
script is caught; use the uninstallBlock and "function uninstall(args)" context
to locate where to change the test.
🪄 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

Run ID: 085c13ad-8930-4fbc-8bf9-ad3f7c245e0a

📥 Commits

Reviewing files that changed from the base of the PR and between eaef339 and c06c544.

📒 Files selected for processing (2)
  • bin/nemoclaw.js
  • test/runner.test.js

VijayKumar383 and others added 2 commits April 4, 2026 13:54
Strengthen the NVIDIA#577 regression check to catch broader curl and bash
uninstallScript execution patterns so remote uninstall fallback cannot
silently regress under small implementation variations.

Made-with: Cursor
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
test/runner.test.js (1)

753-755: ⚠️ Potential issue | 🟠 Major

Harden this regression guard; current pattern is too narrow.

The current check only blocks the exact spawnSync("bash", [uninstallScript...]) form, so a remote fallback can be reintroduced with a different variable/signature and still pass. Also, chained split(...)[1] is brittle.

Suggested hardening
-      const uninstallBlock = src.split("function uninstall(args)")[1].split("function showStatus")[0];
-      expect(uninstallBlock).not.toMatch(/execFileSync\("curl"/);
-      expect(uninstallBlock).not.toMatch(/spawnSync\("bash", \[uninstallScript/);
+      const start = src.indexOf("function uninstall(args)");
+      const end = src.indexOf("function showStatus", start);
+      expect(start).toBeGreaterThan(-1);
+      expect(end).toBeGreaterThan(start);
+      const uninstallBlock = src.slice(start, end);
+      expect(uninstallBlock).not.toMatch(/exec(File)?Sync\(\s*["']curl["']/);
+      expect(uninstallBlock).not.toMatch(/spawnSync\(\s*["']bash["']\s*,\s*\[\s*(?!localScript\b)/);
       expect(uninstallBlock).toContain("Remote uninstall fallback is disabled for security.");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/runner.test.js` around lines 753 - 755, The current test extracts
uninstallBlock via brittle chained splits and only looks for exact patterns
execFileSync("curl" and spawnSync("bash", [uninstallScript), which is too
narrow; update the test to robustly extract the uninstall function body (e.g.,
match the function uninstall(...) { ... } block with a single regex like
/function uninstall\([^)]*\)\s*{[\s\S]*?}/) into the uninstallBlock variable and
change the assertions to reject broader remote-execution patterns such as any
exec/execFile/spawn/spawnSync/child_process usage invoking curl|wget|http(s)
URLs or invoking bash/sh with any argument that contains "uninstallScript" or an
http(s) URL; keep using uninstall and showStatus as anchors to locate the
function body and replace the two strict expect(...).not.toMatch(...) checks
with regexes that cover these wider cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@test/runner.test.js`:
- Around line 753-755: The current test extracts uninstallBlock via brittle
chained splits and only looks for exact patterns execFileSync("curl" and
spawnSync("bash", [uninstallScript), which is too narrow; update the test to
robustly extract the uninstall function body (e.g., match the function
uninstall(...) { ... } block with a single regex like /function
uninstall\([^)]*\)\s*{[\s\S]*?}/) into the uninstallBlock variable and change
the assertions to reject broader remote-execution patterns such as any
exec/execFile/spawn/spawnSync/child_process usage invoking curl|wget|http(s)
URLs or invoking bash/sh with any argument that contains "uninstallScript" or an
http(s) URL; keep using uninstall and showStatus as anchors to locate the
function body and replace the two strict expect(...).not.toMatch(...) checks
with regexes that cover these wider cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7a93459c-ae87-4ae5-9f0d-2140cf93ebb7

📥 Commits

Reviewing files that changed from the base of the PR and between c06c544 and 8426ed6.

📒 Files selected for processing (2)
  • bin/nemoclaw.js
  • test/runner.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • bin/nemoclaw.js

@wscurran wscurran added security Something isn't secure priority: high Important issue that should be resolved in the next release fix labels Apr 6, 2026
@wscurran
Copy link
Copy Markdown
Contributor

wscurran commented Apr 6, 2026

✨ Thanks for submitting this fix, which proposes a way to disable remote uninstall script execution fallback, improving security by requiring manual review.

@cv cv added v0.0.11 Release target v0.0.12 Release target v0.0.13 Release target and removed v0.0.11 Release target v0.0.12 Release target labels Apr 9, 2026
Copy link
Copy Markdown
Contributor

@ericksoa ericksoa left a comment

Choose a reason for hiding this comment

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

Requesting changes: this PR has merge conflicts due to the TS migration (#1673) and the uninstall handler extraction (#1549). The uninstall function was moved out of bin/nemoclaw.js and test/runner.test.js was migrated to TypeScript, so both files this PR touches no longer exist in their original form. The fix itself is correct and wanted, but needs to be re-applied to the new TypeScript locations rather than conflict-resolved. Marking as request-changes to prevent accidental merge.

Saibabu7770 and others added 3 commits April 11, 2026 00:09
Merge remote-tracking branch 'upstream/main' into fix/uninstall-fallback-no-curl-pipe-577.

Resolve bin/nemoclaw.js to the dist bootstrap entrypoint. Remove curl/bash
remote uninstall execution from src/lib/uninstall-command.ts (NVIDIA#577). Update
uninstall-command tests, runner regression guard, and help text.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix priority: high Important issue that should be resolved in the next release security Something isn't secure v0.0.13 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants