Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 61 additions & 3 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,17 @@ the community they pose.
* Avoid exposing low-level or dangerous APIs directly to untrusted users.

* Examples of scenarios that are **not** Node.js vulnerabilities:
* Allowing untrusted users to register SQLite user-defined functions that can
perform arbitrary operations (e.g., closing database connections during query
execution, causing crashes or use-after-free conditions).
* Allowing untrusted users to register SQLite user-defined functions via
`node:sqlite` (`DatabaseSync`) that can perform arbitrary operations
(e.g., closing database connections during query execution, causing crashes
or use-after-free conditions).
* Loading SQLite extensions using the `allowExtension` option in
`DatabaseSync` — this option must be explicitly set to `true` by the
application, and enabling it is the application operator's responsibility.
* Using `node:sqlite` built-in SQL functions or pragmas (e.g.,
`ATTACH DATABASE`) to read or write files — `DatabaseSync` operates with
the same file-system access as the process itself, and it is the
application's responsibility to restrict what SQL is executed.
* Exposing `child_process.exec()` or similar APIs to untrusted users without
proper input validation, allowing command injection.
* Allowing untrusted users to control file paths passed to file system APIs
Expand Down Expand Up @@ -362,6 +370,56 @@ the community they pose.
responsibility to properly handle errors by attaching appropriate
`'error'` event listeners to EventEmitters that may emit errors.

#### Permission Model Boundaries (`--permission`)

The Node.js [Permission Model](https://nodejs.org/api/permissions.html)
(`--experimental-permission`) is an opt-in mechanism that limits which
resources a Node.js process may access. It is designed to reduce the blast
radius of mistakes in trusted application code, **not** to act as a security
boundary against intentional misuse or a compromised process.

The following are **not** vulnerabilities in Node.js:

* **Operator-controlled flags**: Behavior unlocked by flags the operator
explicitly passes (e.g., `--localstorage-file`) is the operator's
responsibility. The permission model does not restrict how Node.js behaves
when the operator intentionally configures it.

* **`node:sqlite` and the permission model**: `DatabaseSync` operates with the
same file-system privileges as the process. Using SQL pragmas or built-in
SQLite mechanisms (e.g., `ATTACH DATABASE`) to access files does not bypass
the permission model — the permission model does not intercept SQL-level
file operations.

* **Path resolution and symlinks**: `fs.realpathSync()`, `fs.realpath()`, and
similar functions resolve a path to its canonical form before the permission
check is applied. Accessing a file through a symlink that resolves to an
allowed path is the intended behavior, not a bypass. TOCTOU races on
symlinks that resolve within the allowed list are similarly not considered
permission model bypasses.

* **`worker_threads` with modified `execArgv`**: Workers inherit the permission
restrictions of their parent process. Passing an empty or modified `execArgv`
to a worker does not grant it additional permissions.

#### V8 Sandbox

The V8 sandbox is an in-process isolation mechanism internal to V8 that is not
a Node.js security boundary. Node.js does not guarantee or document the V8
sandbox as a security feature, and it is not enabled in a way that provides
security guarantees in production Node.js builds. Reports about escaping the V8
sandbox are not considered Node.js vulnerabilities; they should be reported
directly to the [V8 project](https://v8.dev/docs/security-bugs).

#### CRLF Injection in `writeEarlyHints()`

`ServerResponse.writeEarlyHints()` accepts a `link` header value that is set
by the application. Passing arbitrary strings, including CRLF sequences, as
the `link` value is an application-level misuse of the API, not a Node.js
vulnerability. Node.js validates the structure of Early Hints per the HTTP spec
but does not sanitize free-form application data passed to it; that is the
application's responsibility.
Comment on lines +414 to +421
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one seems a bit specific. I feel like we probably don't need to go down the line of exhaustively listing every received wontfix...

Copy link
Member Author

@RafaelGSS RafaelGSS Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just an attempt to reduce the AI-sloop. If it fixes the problem, we might want to go down that line... in a separate file, possibly more specific to AI.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit disheartening to see since I decided to discuss this very issue with @RafaelGSS first to understand what falls in or out of the node js threat model.

Yes AI was used in the discovery, but there are three points that led to the discussion to seek clarification;

  1. CWE-444 is given as an example vulnerability in this doc
  2. The wording;

if the data passing through Node.js to/from the application can trigger actions other than those documented for the APIs

  1. The paragraph (emphasis mine);

In addition to addressing vulnerabilities based on the above, the project works to avoid APIs and internal implementations that make it "easy" for application code to use the APIs incorrectly in a way that results in vulnerabilities within the application code itself. While we don’t consider those vulnerabilities in Node.js itself and will not necessarily issue a CVE, we do want them to be reported privately to Node.js first. We often choose to work to improve our APIs based on those reports and issue fixes either in regular or security releases depending on how much of a risk to the community they pose.

Despite AI involvement, it presented as an issue that ought to be addressed, if the means of reporting was incorrect, I apologise, I thought I did the right thing, but I do acknowledge that the use of AI in security is only going to exacerbate claims of vulnerabilities.

Lastly, here's the PR to actually try and harden/sanitise from CRLF through writeEarlyHints() to prevent this very footgun #61897. It still holds that's the applications responsibility for those header name/values, but at least there's some mitigation and consistency with other header setting functions.

Rather than specifically calling out CRLF in writeEarlyHints, could this example be updated to demonstrate the differentiator between an applications responsibility and node js, which I read as the intent of this. An issue within JSON.parse might be the responsibility of node js but the resulting value given some remote data is the applications.


## Assessing experimental features reports

Experimental features are eligible for security reports just like any other
Expand Down
Loading