fix: replace predictable temp filenames with mkdtempSync#1105
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughReplaced predictable temp filenames with mkdtemp-scoped temp files and introduced helpers Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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.
Pull request overview
This PR addresses a local symlink/TOCTOU risk caused by predictable temporary filenames in onboarding probe/model-fetch helpers by switching to fs.mkdtempSync()-backed temp paths.
Changes:
- Added a
secureTempFile(prefix, ext)helper to generate temp file paths inside mkdtemp-created directories. - Replaced 6 predictable
/tmp/...Date.now()+Math.random()temp filename constructions withsecureTempFile(...). - Updated the sandbox sync script test to assert the new mkdtemp-based path shape and to clean up the created temp directory.
Reviewed changes
Copilot reviewed 1 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
bin/lib/onboard.js |
Introduces secureTempFile and migrates probe/model-fetch/sync-script temp paths away from predictable names. |
test/onboard.test.js |
Adjusts the sandbox sync temp-file test for mkdtemp-based paths and cleans up the temp directory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
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 `@bin/lib/onboard.js`:
- Around line 539-543: The temp directories created by secureTempFile() are
never removed; modify writeSandboxConfigSyncFile (and all places that delete the
returned temp file) to remove the temp file's parent directory instead of only
unlinking the file. Specifically: when cleaning up values returned by
secureTempFile() (e.g., the path produced by writeSandboxConfigSyncFile and
other secureTempFile callers), compute the parent directory
(path.dirname(returnedPath)) and remove that directory (recursively/forcibly)
rather than just fs.unlink/fs.unlinkSync on the file; update all cleanup sites
that currently unlink the file to remove the parent dir to avoid leaving empty
temp dirs.
🪄 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: ed611c39-c8ec-4bbc-a2aa-ea9a3e893649
📒 Files selected for processing (2)
bin/lib/onboard.jstest/onboard.test.js
|
✨ Thanks for submitting this PR with a detailed summary, it addresses a security bug with predictable temp filenames and proposes a fix to improve the security of NemoClaw, which could prevent potential vulnerabilities. |
4884e10 to
9b7898d
Compare
There was a problem hiding this comment.
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/onboard.test.js`:
- Line 442: The cleanup call unconditionally calls
fs.rmSync(path.dirname(scriptFile), { recursive: true, force: true }) which can
delete the system temp root if writeSandboxConfigSyncFile regresses; before
calling fs.rmSync, add a strict guard that ensures the target dir is a
subdirectory of os.tmpdir() (e.g., compute tempRoot = os.tmpdir(), targetDir =
path.resolve(path.dirname(scriptFile)), then verify targetDir !== tempRoot and
path.relative(tempRoot, targetDir) does not start with '..' and does start with
the path.sep or a non-empty relative path) and only then perform fs.rmSync;
reference path.dirname(scriptFile), writeSandboxConfigSyncFile, fs.rmSync and
os.tmpdir() when locating the code to change.
🪄 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: dc7963be-a3e1-484e-81dc-0ee47bbe65a4
📒 Files selected for processing (2)
bin/lib/onboard.jstest/onboard.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
- bin/lib/onboard.js
bd8cbf4 to
3c769e8
Compare
There was a problem hiding this comment.
@BenediktSchackenberg thanks for this improvement!
Two minor observations:
Test cleanup duplicates cleanupTempDir logic — the finally block in the test reimplements the same parent-dir guard inline. A // mirrors cleanupTempDir() comment would help readers see the connection.
Orphaned temp dirs on crash — if the process dies between secureTempFile() and cleanupTempDir(), the mkdtemp directory is left behind. Same behavior as before (leaked files) so no regression, but worth noting as a known limitation.
Also pls resolve conflicts with main and we will keep an eye out to get this to finish line
Add secureTempFile(prefix, ext) helper using fs.mkdtempSync() to create temp files inside OS-level unique directories, preventing symlink attacks on predictable /tmp paths. Add cleanupTempDir(filePath, expectedPrefix) guard that verifies the parent directory matches the expected mkdtemp prefix before calling fs.rmSync recursive, preventing accidental deletion of the system temp root on regression. Changes: - runCurlProbe: replace Date.now()+Math.random() with secureTempFile - writeSandboxConfigSyncFile: use secureTempFile, drop tmpDir param - All cleanup sites use cleanupTempDir guard - Test updated for new function signature and mkdtemp assertions Closes NVIDIA#1093
3c769e8 to
f6f805e
Compare
|
Thanks @prekshivyas! Good catches. Test cleanup comment — added Orphaned temp dirs on crash — agreed, that's a known limitation. Same behavior as before (leaked individual files vs leaked directories), so no regression. Could be improved with a periodic Conflicts — rebased onto latest main. Single clean commit, signed. |
## Summary Six functions in `bin/lib/onboard.js` create temporary files using `Date.now()` and `Math.random().toString(36)`, both of which are predictable. A local attacker can win a TOCTOU race to pre-create a symlink at the predicted path in `/tmp`, enabling: 1. **Data exfiltration** — redirect curl output (API responses with model data) to an attacker-controlled location 2. **Script injection** — via `writeSandboxConfigSyncFile`, inject a malicious script that gets piped into `openshell sandbox connect` ## Changes **`bin/lib/onboard.js`:** - Added `secureTempFile(prefix, ext)` helper that uses `fs.mkdtempSync()` (OS-level `mkdtemp` syscall with cryptographically random suffix) - Replaced all 6 predictable temp file constructions: - `probeOpenAiLikeEndpoint` (line ~667) - `probeAnthropicEndpoint` (line ~711) - `fetchNvidiaEndpointModels` (line ~857) - `fetchOpenAiLikeModels` (line ~911) - `fetchAnthropicModels` (line ~947) - `writeSandboxConfigSyncFile` (line ~527) **`test/onboard.test.js`:** - Updated the sync file test to validate the new mkdtemp-based path structure instead of the old predictable pattern ## Why this approach The file already uses `fs.mkdtempSync()` securely in two other places (lines 1781 and 2710), making this fix consistent with existing code patterns rather than introducing new dependencies. The remaining `Date.now()` usage in `patchStagedDockerfile` is a build identifier written into the Dockerfile, not a temp filename — left unchanged. Fixes #1093 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved temporary-file handling: sync scripts and downloaded responses are now written to securely named temp subdirectories and cleaned up at the directory level to reduce leftover artifacts. * **Tests** * Updated tests to validate new temp-file placement and naming pattern, exact script contents, and tightened directory-level cleanup checks. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
## Summary Six functions in `bin/lib/onboard.js` create temporary files using `Date.now()` and `Math.random().toString(36)`, both of which are predictable. A local attacker can win a TOCTOU race to pre-create a symlink at the predicted path in `/tmp`, enabling: 1. **Data exfiltration** — redirect curl output (API responses with model data) to an attacker-controlled location 2. **Script injection** — via `writeSandboxConfigSyncFile`, inject a malicious script that gets piped into `openshell sandbox connect` ## Changes **`bin/lib/onboard.js`:** - Added `secureTempFile(prefix, ext)` helper that uses `fs.mkdtempSync()` (OS-level `mkdtemp` syscall with cryptographically random suffix) - Replaced all 6 predictable temp file constructions: - `probeOpenAiLikeEndpoint` (line ~667) - `probeAnthropicEndpoint` (line ~711) - `fetchNvidiaEndpointModels` (line ~857) - `fetchOpenAiLikeModels` (line ~911) - `fetchAnthropicModels` (line ~947) - `writeSandboxConfigSyncFile` (line ~527) **`test/onboard.test.js`:** - Updated the sync file test to validate the new mkdtemp-based path structure instead of the old predictable pattern ## Why this approach The file already uses `fs.mkdtempSync()` securely in two other places (lines 1781 and 2710), making this fix consistent with existing code patterns rather than introducing new dependencies. The remaining `Date.now()` usage in `patchStagedDockerfile` is a build identifier written into the Dockerfile, not a temp filename — left unchanged. Fixes NVIDIA#1093 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved temporary-file handling: sync scripts and downloaded responses are now written to securely named temp subdirectories and cleaned up at the directory level to reduce leftover artifacts. * **Tests** * Updated tests to validate new temp-file placement and naming pattern, exact script contents, and tightened directory-level cleanup checks. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
## Summary Six functions in `bin/lib/onboard.js` create temporary files using `Date.now()` and `Math.random().toString(36)`, both of which are predictable. A local attacker can win a TOCTOU race to pre-create a symlink at the predicted path in `/tmp`, enabling: 1. **Data exfiltration** — redirect curl output (API responses with model data) to an attacker-controlled location 2. **Script injection** — via `writeSandboxConfigSyncFile`, inject a malicious script that gets piped into `openshell sandbox connect` ## Changes **`bin/lib/onboard.js`:** - Added `secureTempFile(prefix, ext)` helper that uses `fs.mkdtempSync()` (OS-level `mkdtemp` syscall with cryptographically random suffix) - Replaced all 6 predictable temp file constructions: - `probeOpenAiLikeEndpoint` (line ~667) - `probeAnthropicEndpoint` (line ~711) - `fetchNvidiaEndpointModels` (line ~857) - `fetchOpenAiLikeModels` (line ~911) - `fetchAnthropicModels` (line ~947) - `writeSandboxConfigSyncFile` (line ~527) **`test/onboard.test.js`:** - Updated the sync file test to validate the new mkdtemp-based path structure instead of the old predictable pattern ## Why this approach The file already uses `fs.mkdtempSync()` securely in two other places (lines 1781 and 2710), making this fix consistent with existing code patterns rather than introducing new dependencies. The remaining `Date.now()` usage in `patchStagedDockerfile` is a build identifier written into the Dockerfile, not a temp filename — left unchanged. Fixes NVIDIA#1093 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved temporary-file handling: sync scripts and downloaded responses are now written to securely named temp subdirectories and cleaned up at the directory level to reduce leftover artifacts. * **Tests** * Updated tests to validate new temp-file placement and naming pattern, exact script contents, and tightened directory-level cleanup checks. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
Summary
Six functions in
bin/lib/onboard.jscreate temporary files usingDate.now()andMath.random().toString(36), both of which are predictable. A local attacker can win a TOCTOU race to pre-create a symlink at the predicted path in/tmp, enabling:writeSandboxConfigSyncFile, inject a malicious script that gets piped intoopenshell sandbox connectChanges
bin/lib/onboard.js:secureTempFile(prefix, ext)helper that usesfs.mkdtempSync()(OS-levelmkdtempsyscall with cryptographically random suffix)probeOpenAiLikeEndpoint(line ~667)probeAnthropicEndpoint(line ~711)fetchNvidiaEndpointModels(line ~857)fetchOpenAiLikeModels(line ~911)fetchAnthropicModels(line ~947)writeSandboxConfigSyncFile(line ~527)test/onboard.test.js:Why this approach
The file already uses
fs.mkdtempSync()securely in two other places (lines 1781 and 2710), making this fix consistent with existing code patterns rather than introducing new dependencies.The remaining
Date.now()usage inpatchStagedDockerfileis a build identifier written into the Dockerfile, not a temp filename — left unchanged.Fixes #1093
Summary by CodeRabbit
Refactor
Tests
Signed-off-by: Benedikt Schackenberg 6381261+BenediktSchackenberg@users.noreply.github.com