Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
This library provides somewhat saner interfaces to Node's child_process module. It's still growing, and most of the interfaces there don't have analogs here yet.
The interfaces in this library conform to Joyent's Best Practices for Error Handling in Node.js. Most notably:
The only interfaces currently provided are:
(args, callback)
: like
child_process.execFile
, but all operational errors are emitted
asynchronously, errors are more descriptive, and there's a crisper summary of
exactly what happened.(args)
:
lower-level function for taking the result of one of Node's child_process
functions and producing a normalized summary of what happened.One of the biggest challenges in using Node's child_process interfaces is properly interpreting the result. When you kick off a child process (as with fork/exec), there are basically four possible outcomes:
error
is non-null, status
is null, and signal
is null)error
is non-null, status
is null, and signal
is non-null)error
is non-null, status
is a non-zero integer, and signal
is null).error
is null, status
is 0, and signal
is null.)Most code doesn't handle (1) at all, since it usually results in the child_process function throwing an exception rather than calling your callback. Most use-cases want to treat (1), (2), and (3) as failure cases and generate a descriptive error for them, but the built-in Errors are not very descriptive.
The interfaces here attempt to make the common case very easy (providing a
descriptive, non-null Error in cases (1) through (3), but not (4)), while still
allowing more complex callers to easily determine exactly what happened. These
interfaces do this by taking the result of the underlying Node API function and
producing an info
object with properties:
Like the built-in child_process.execFile
, this function forks a child process,
exec's the requested command, waits for it to exit, and captures the full stdout
and stderr. The file should be an executable on the caller's PATH. It is
not passed through bash -c
as would happen with child_process.exec
.
forkExecWait(args, callback)
The main argument is:
[ 'ls', '-l' ]
.The following arguments have the same semantics as for Node's built-in
child_process.execFile
except where otherwise noted:
stderr
will be trimmed and included in the error message.
Defaults to false
.The return value is the same as child_process.execFile
except when that
function would throw an exception, in which case this function will return
null
and the error that would have been thrown is instead emitted to the
callback (as you'd probably have expected Node to do).
The callback is invoked as callback(err, info)
, where info
always has
properties:
info.error
is the same as the err
argument.As described above, the interface throws on programmer errors, and these should not be handled. Operational errors are emitted asynchronously. See the four possible outcomes described above for what those are.
Normal command:
forkExecWait({
'argv': [ 'echo', 'hello', 'world' ]
}, function (err, info) {
console.log(info);
});
{ error: null,
status: 0,
signal: null,
stdout: 'hello world\n',
stderr: '' }
Successful fork/exec, command fails:
forkExecWait({
'argv': [ 'grep', 'foobar' '/nonexistent_file' ]
}, function (err, info) {
console.log(info);
});
{ error:
{ [VError: exec "grep foobar /nonexistent_file": exited with status 2]
jse_shortmsg: 'exec "grep foobar /nonexistent_file"',
jse_summary: 'exec "grep foobar /nonexistent_file": exited with status 2',
jse_cause:
{ [VError: exited with status 2]
jse_shortmsg: 'exited with status 2',
jse_summary: 'exited with status 2',
message: 'exited with status 2' },
message: 'exec "grep foobar /nonexistent_file": exited with status 2' },
status: 2,
signal: null,
stdout: '',
stderr: 'grep: /nonexistent_file: No such file or directory\n' }
Failed fork/exec: command not found:
forkExecWait({
'argv': [ 'nonexistent', 'command' ]
}, function (err, info) {
console.log(info);
});
{ error:
{ [VError: exec "nonexistent command": spawn nonexistent ENOENT]
jse_shortmsg: 'exec "nonexistent command"',
jse_summary: 'exec "nonexistent command": spawn nonexistent ENOENT',
jse_cause:
{ [Error: spawn nonexistent ENOENT]
code: 'ENOENT',
errno: 'ENOENT',
syscall: 'spawn nonexistent',
path: 'nonexistent',
cmd: 'nonexistent command' },
message: 'exec "nonexistent command": spawn nonexistent ENOENT' },
status: null,
signal: null,
stdout: '',
stderr: '' }
Failed fork/exec: command is not executable (note: Node throws on this, while this library emits an error asynchronously, since this is an operational error):
forkExecWait({
'argv': [ '/dev/null' ]
}, function (err, info) {
console.log(info);
});
{ error:
{ [VError: exec "/dev/null": spawn EACCES]
jse_shortmsg: 'exec "/dev/null"',
jse_summary: 'exec "/dev/null": spawn EACCES',
jse_cause: { [Error: spawn EACCES] code: 'EACCES', errno: 'EACCES', syscall: 'spawn' },
message: 'exec "/dev/null": spawn EACCES' },
status: null,
signal: null,
stdout: '',
stderr: '' }
Command times out (killed by our SIGKILL after 3 seconds):
forkExecWait({
'argv': [ 'sleep', '4' ],
'timeout': 3000,
}, function (err, info) {
console.log(info);
});
{ error:
{ [VError: exec "sleep 2": unexpectedly terminated by signal SIGKILL]
jse_shortmsg: 'exec "sleep 2"',
jse_summary: 'exec "sleep 2": unexpectedly terminated by signal SIGKILL',
jse_cause:
{ [VError: unexpectedly terminated by signal SIGKILL]
jse_shortmsg: 'unexpectedly terminated by signal SIGKILL',
jse_summary: 'unexpectedly terminated by signal SIGKILL',
message: 'unexpectedly terminated by signal SIGKILL' },
message: 'exec "sleep 2": unexpectedly terminated by signal SIGKILL' },
status: null,
signal: 'SIGKILL',
stdout: '',
stderr: '' }
This lower-level function takes the results of one of the child_process
functions and produces the info
object described above, including a more
descriptive Error (if there was one).
interpretChildProcessResult(args)
Named arguments are:
null
or
an instance of Error.The return value is an info
object with the error
, status
, and signal
properties described above.
As described above, the interface throws on programmer errors, and these should not be handled. There are no operational errors for this interface.
Contributions welcome. Code should be "make prepush" clean. To run "make prepush", you'll need these tools:
If you're changing something non-trivial or user-facing, you may want to submit an issue first.
FAQs
sane child process library
The npm package forkexec receives a total of 7 weekly downloads. As such, forkexec popularity was classified as not popular.
We found that forkexec demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 14 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.