~ 4 min read

Introducing Node.js Security Permissions Model, Threat Model, and Security Releases

share this story on
Learn how to secure your Node.js applications with the new Permissions Model, stay informed about security releases, and understand the Node.js Security Threat.

In this blog post, I’ll shortly review some of the built-in security features in Node.js that can help you secure your applications. These features include the new and still experimental Node.js Permissions Model, which allows you to enforce code execution boundaries, and the Node.js Security Threat Model, which outlines potential threats to Node.js applications, being aware on Node.js Security Releases and how to keep up with them.

Node.js Permissions Model: Enforcing Code Execution Boundaries

Node.js 18 introduces a new experimental feature now available in Node.js 20 too: the permissions model. This model aims to enhance security by allowing granular control over what resources code can access within the Node.js process.

Traditionally, Node.js code has relied on a privileged execution environment. This means code could access most system resources by default. For example, a Node.js application could read and write files arbitrarily on the file system, open network connections, and spawn child processes without any restrictions.

The Node.js Permissions Model operates with two key concepts: permissions and flags. Permissions define specific actions code can perform (e.g., fs.read, fs.write), while flags control the overall model behavior and allowed operations.

By default, the Permissions Model is disabled. To activate it, use the --experimental-permission flag when starting Node.js. This flag immediately restricts access to all available permissions unless overridden with specific allow flags. Here’s what happens when you run your application without explicit permissions:

$ node --experimental-permission index.js

  const result = internalModuleStat(filename);

Error: Access to this API has been restricted

This error message indicates that the fs module’s stat function, used for file system access, is restricted by the Permissions Model.

To enable specific permissions, use the --experimental-permission flag followed by the permission name. For example, to allow file system read access, use the following command:

$ node --experimental-permit=fs.read index.js

Other supported flags are for example:

  • --allow-child-process: Allows spawning child processes.
  • --allow-worker: Allows creating worker threads using node:worker_threads.
  • --allow-addons: Allows using native addons.
  • --allow-fs-read and --allow-fs-write: Control file system access permissions.

You can then also check for permissions in your code using the permissions module so that you can assert at runtime whether the Node.js process has the necessary permissions to execute specific operations.

// true (assuming write access is allowed)

// Might be false if write access is restricted to specific folders
process.permission.has('fs.write', '/home/user/protected-folder');

Keeping Up with Node.js Security Releases

Node.js releases security updates periodically to address vulnerabilities reported by the community. These vulnerabilities are documented as Common Vulnerabilities and Exposures (CVEs). Let’s look at some recent CVEs to understand the potential risks:

  • CVE-2024-27983 (High Severity): This vulnerability in Node.js HTTP/2 server could lead to Denial-of-Service (DoS) attacks. An attacker could exploit this by sending malformed HTTP requests.

  • CVE-2024-21892 (High Severity): This critical vulnerability allows code injection and privilege escalation through Linux capabilities. Attackers could potentially gain unauthorized access to your system. These are just a few examples, and new vulnerabilities are discovered regularly.

Staying Informed about Security Updates:

Here are practical steps to ensure you’re notified about security updates:

  • Subscribe to the Node.js security mailing list: The nodejs-sec mailing list provides low-volume announcements about security vulnerabilities and related releases.

  • Follow the official Node.js blog: The Node.js blog regularly publishes articles about security releases. Pay attention to posts with titles like “Security Releases”.

  • Utilize Node.js version management tools: Tools like nvm and fnm make it easy to switch between Node.js versions. They also provide commands to list available versions and check for updates.

  • Use Official Node.js Docker Images: The official Node.js Docker Hub images are built from secure base images and often include the latest security patches. Pin image versions and avoid using the latest tag when pulling Node.js Docker images. Specify a specific version number to ensure consistent security posture across deployments.

Node.js Security Threat Model

Understanding the threat model for Node.js applications is crucial for building secure systems, and a community of Node.js volunteers maintains a security working group that focuses on identifying and mitigating security risks.

One of the outcomes of this work is the Node.js threat model. This document outlines the potential threats to Node.js applications and provides guidance on how to mitigate them. Some of the key threats include:

  • The loss of integrity or confidentiality of data protected through the correct use of Node.js APIs.
  • The loss of availability of services provided by Node.js applications, including degradation of performance.

You are also encouraged to report security vulnerabilities in Node.js through the Node.js JavaScript Runtime project on HackerOne.

share this story on