fix(security): shell-quote sandboxName in exec and DNS proxy commands#1392
fix(security): shell-quote sandboxName in exec and DNS proxy commands#1392latenighthackathon wants to merge 3 commits intoNVIDIA:mainfrom
Conversation
sandboxName and GATEWAY_NAME are interpolated into shell command strings passed to run()/runCapture() without shellQuote(), which is inconsistent with other user-controlled values in the same file (lines 460, 1438, 3005). Wrap both values with shellQuote() to prevent shell metacharacter interpretation. Add regression test that scans onboard.js for any unquoted sandboxName in run/runCapture calls. Closes NVIDIA#1391 Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughApplied shell quoting to Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
test/shellquote-sandbox.test.js (1)
22-35: Strengthen the scanner to handle multilinerun/runCapturecalls.The current per-line check can miss unquoted
${sandboxName}when the call and template literal span different lines. A block-level scan would make this regression test reliable.Proposed refactor
it("does not have unquoted sandboxName in runCapture or run calls", () => { - const lines = src.split("\n"); const violations = []; - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if ( - (line.includes("run(") || line.includes("runCapture(")) && - line.includes("${sandboxName}") && - !line.includes("shellQuote(sandboxName)") - ) { - violations.push(`Line ${i + 1}: ${line.trim()}`); - } - } + const callRegex = /\b(run|runCapture)\(\s*`([\s\S]*?)`\s*(?:,|\))/g; + let match; + while ((match = callRegex.exec(src)) !== null) { + const command = match[2]; + if (command.includes("${sandboxName}") && !command.includes("${shellQuote(sandboxName)}")) { + const line = src.slice(0, match.index).split("\n").length; + violations.push(`Line ${line}: ${match[1]}(...) contains unquoted \${sandboxName}`); + } + } expect(violations).toEqual([]); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/shellquote-sandbox.test.js` around lines 22 - 35, The test currently scans line-by-line so it misses multiline run/runCapture calls; instead treat the file as a single string and search block-wise: iterate matches of /\\b(run|runCapture)\\s*\\((?:[\\s\\S]*?)`([\\s\\S]*?)`[\\s\\S]*?\\)/g (or equivalent) against src and for each match check if the captured template contains "${sandboxName}" and does not contain "shellQuote(sandboxName)"; push a violation with context if so and assert violations is empty. Update references in the test to use src (the full file string), the run/runCapture regex matcher, and the violations array logic accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@test/shellquote-sandbox.test.js`:
- Around line 22-35: The test currently scans line-by-line so it misses
multiline run/runCapture calls; instead treat the file as a single string and
search block-wise: iterate matches of
/\\b(run|runCapture)\\s*\\((?:[\\s\\S]*?)`([\\s\\S]*?)`[\\s\\S]*?\\)/g (or
equivalent) against src and for each match check if the captured template
contains "${sandboxName}" and does not contain "shellQuote(sandboxName)"; push a
violation with context if so and assert violations is empty. Update references
in the test to use src (the full file string), the run/runCapture regex matcher,
and the violations array logic accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 378a2e84-f191-436d-b392-67ab422ed1ca
📒 Files selected for processing (2)
bin/lib/onboard.jstest/shellquote-sandbox.test.js
Line-by-line scanning misses multiline run()/runCapture() calls. Switch to a regex that matches the full call including the template literal, so violations spanning multiple lines are caught. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
Builds on NVIDIA#1392 by validating sandboxName overrides at the createSandbox boundary, moving the dashboard readiness check onto the structured OpenShell helper path, and running the DNS proxy setup through argv-style execution instead of bash -c interpolation. Adds regression coverage for the new runner helper, invalid sandboxNameOverride rejection, and the createSandbox command paths. Co-authored-by: latenighthackathon <latenighthackathon@users.noreply.github.com> Signed-off-by: 13ernkastel <LennonCMJ@live.com>
Summary
sandboxNamewithshellQuote()in the dashboard readiness check (openshell sandbox exec)GATEWAY_NAMEandsandboxNamewithshellQuote()in the DNS proxy setup commandonboard.jsfor any unquotedsandboxNameinrun()/runCapture()callsProblem
sandboxNameis interpolated into shell command strings passed torun()/runCapture()(which execute viabash -c) withoutshellQuote(). The same file imports and usesshellQuote()for other user-controlled values (lines 460, 1438, 3005) but omits it here.Without quoting:
With quoting:
Test plan
shellQuote()output in Docker (node:22-slim) for semicolon, subshell, and pipe injection payloadsCloses #1391
Signed-off-by: latenighthackathon latenighthackathon@users.noreply.github.com
Summary by CodeRabbit
Bug Fixes
Tests