Representative interview topic

Backend interview: How would you roll out the Node.js Permission Model?

BackendHard
Offer.cc Editorial TeamPublished Updated

Question

Your team wants Node.js to restrict file, network, and child-process access. How would you evaluate the security boundary and enable it safely in production?

Scenario

You maintain a containerized Node.js API with third-party dependencies. It reads configuration, accesses object storage, and occasionally launches an image-processing child process. Security proposes --permission with only the required file, network, and child-process grants. Explain the threat model, permission inventory, compatibility tests, monitoring, and rollback.

What the interviewer evaluates

  • Knowing the Permission Model is a seat belt for trusted code, not a sandbox for malicious code.
  • Decomposing file, network, child-process, worker, and native-addon capabilities into least privilege.
  • Recognizing symlinks, existing file descriptors, initialization order, and inheritance limits.
  • Designing a canary, useful denial telemetry, and a business-safe rollback.

Clarifying questions

Confirm the Node version, entrypoint, native addons, worker/FFI/WASI needs, paths and domains, and whether the application must spawn processes. Check existing container and OS controls such as seccomp, user identity, and read-only filesystems so Node is not treated as the only defense.

30-second answer

I would treat it as least-privilege control for trusted code, not a complete defense against malicious dependencies. Build grants from production dependency and runtime audits for fs.read, fs.write, network, child, and worker scopes. Enable it in shadow mode and 1% of traffic, record ERR_ACCESS_DENIED and latency, and test native addons, symlinks, and existing descriptors. Keep container isolation. If error rate or a critical dependency regresses, remove the startup flag to roll back and refine the inventory.

Step-by-step reasoning

1. Define the security boundary

Node describes the Permission Model as process-resource restriction and explicitly says it does not protect against malicious code; Node trusts code it is asked to run. It reduces accidental access by trusted applications, but cannot replace containers, OS users, seccomp, or dependency-supply-chain controls.

2. Build the permission inventory

Start with default deny. Grant --allow-fs-read only to configuration and static paths, narrow --allow-fs-write to temporary output, and --allow-net to required object-storage domains. Add --allow-child-process, --allow-worker, or --allow-addons only with a documented need. Version the grants and require service-owner review.

3. Verify runtime behavior

Cover startup, health checks, uploads, image processing, scheduled work, and error paths. Verify process.permission.has() and remember that permission.drop() is irreversible and affects future checks only; it does not close open descriptors, sockets, or workers. Test symlinks, native addons, npx, and child-process boundaries.

4. Canary and rollback

Enable it first in staging and one stateless instance. Collect denied resource class, stack, version, and tenant without logging sensitive values. Gate expansion on error rate, P95, startup success, and completed business jobs. Rollback is removing --permission or the relevant --allow-* flags; retain read-only, non-root, and network controls at the container layer.

High-quality sample answer

I would draw a permission matrix: read-only configuration, a writable temporary directory, required object-storage domains, the image-conversion child process, and no worker or native addon without a business reason. Permission Model restricts fs by default, so startup parameters grant each capability explicitly. I would version those parameters, run integration scenarios in CI with the smallest image, and verify every route and background job. The canary covers one stateless class, aggregates ERR_ACCESS_DENIED, and hashes resource paths. I would specifically test symlinks, existing descriptors, and the fact that child processes and workers do not inherit the model in the same way; malicious-code risk remains with container and OS isolation. Expand only after startup, P95, denial, and job-completion gates pass. If a critical dependency is denied or errors rise, remove the flag to restore behavior, then update the inventory before retrying.

Common mistakes

  • Claiming the Permission Model safely runs malicious third-party packages.
  • Granting --allow-fs-read=* and --allow-fs-write=* without need.
  • Ignoring native addons, workers, child processes, WASI, FFI, or network restrictions.
  • Assuming permission.drop() closes already-open descriptors, sockets, or workers.
  • Testing only local startup and missing npx, symlinks, or real background jobs.

Follow-up questions and responses

“Can it replace a container sandbox?”

No. Node explicitly says it does not protect against malicious code. Combine it with non-root execution, read-only filesystems, seccomp, network policy, and dependency-supply-chain controls.

“Why can the service still not read a file?”

Check the entrypoint and configured path, wildcard behavior, and whether initialization reads occur after the model is established. Use permission.has() and denial events to locate the missing grant.

“How do you allow image processing?”

Grant --allow-child-process separately, constrain the executable and input/output directories, and keep OS and container restrictions. If a library call can replace the child process, remove that permission instead.

Public sources

Related questions