Node.js applications often run with more operating-system authority than their code needs. A build script may need to read one source tree, yet it can also open network connections, inspect unrelated files, or launch another process. The Node.js Permission Model gives teams a way to narrow those capabilities at runtime. The permission model narrows authority without replacing an operating-system sandbox.
What the flag changes
Starting Node.js with --permission restricts several built-in capabilities. The documented scopes cover file system reads and writes, network access, child processes, worker threads, native addons, WASI, FFI, and the inspector in versions that support those controls. Access is granted selectively with flags such as --allow-fs-read, --allow-fs-write, --allow-child-process, --allow-worker, and --allow-net.
That design works best when the application has a short, known list of resources. A content renderer that only reads templates and writes to a temporary directory can receive those two paths and little else. A command-line tool that needs a child process should be reviewed before --allow-child-process is added. The same applies to worker threads, because a worker can perform work outside the main thread's program flow.
The flag is a policy layer inside Node.js. It does not replace file ownership, Unix users, containers, mandatory access control, or network segmentation.
Child processes do not inherit the policy
The permission state belongs to the current Node.js process. A child process that starts its own Node.js runtime does not automatically inherit the parent's restrictions. Code that is allowed to spawn a process can therefore invoke a different executable with a broader configuration, or start Node.js again without the same flags.
This matters in build and automation systems. Suppose the main process is limited to /srv/app/src for reads. If it can launch /bin/sh, the shell's ability to read files is governed by the operating-system identity, not the parent's Node.js filesystem allowlist. The practical control is to avoid granting child-process access unless the parent truly needs it, then constrain the child through the same OS account and container policy.
Worker threads need their own test
The model also has to be evaluated at worker creation. A separate worker runs with its own execution context, and access to worker creation is a permission in its own right. A test that exercises only the main thread can miss code paths that start a worker after a feature flag changes.
Include a negative test for each scope. Start the application with the intended flags, call a denied operation, and confirm that it fails with an error your monitoring can recognize. Then check that the process still has only the access it needs after the worker or child is created.
Existing handles need attention
Permission checks apply when an operation is attempted. A policy change does not close file descriptors, sockets, child processes, or worker threads that were already opened. If startup code creates a broad connection before dropping privileges or switching policy, the later policy can be narrower than the live process.
The inspector has a related operational limit. The documentation notes that same-user mechanisms can affect another process even when the normal permission scopes do not cover that path. Teams running multiple Node.js services under one OS account should treat that shared identity as part of the boundary. Separate service accounts reduce the reach of same-user actions and make process control easier to audit.
A defensible deployment check
Use the smallest allowlist that satisfies a measured workflow. Add --allow-child-process and --allow-worker only after the code owner explains why the application cannot perform the task in-process. Run from a clean working directory, test absolute and relative paths, and verify behavior after a restart.
Finally, log the effective launch command as part of deployment evidence. A permission model that exists only in a developer's shell history will disappear when the service moves to another unit file. The useful result is a short list of granted scopes, a smaller list of denied tests, and an OS boundary that remains in force if Node.js code escapes its intended path.