From e17f8900d9c8e3c53d3e05fa06e127763568ba35 Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Thu, 9 Apr 2026 12:41:44 -0300 Subject: [PATCH 1/2] lib,permission: add permission.drop Signed-off-by: RafaelGSS --- doc/api/permissions.md | 32 +++- doc/api/process.md | 61 +++++++ lib/internal/process/permission.js | 12 ++ lib/internal/process/pre_execution.js | 3 +- src/permission/addon_permission.cc | 6 + src/permission/addon_permission.h | 3 + src/permission/child_process_permission.cc | 6 + src/permission/child_process_permission.h | 3 + src/permission/fs_permission.cc | 92 ++++++++++ src/permission/fs_permission.h | 9 + src/permission/inspector_permission.cc | 6 + src/permission/inspector_permission.h | 3 + src/permission/net_permission.cc | 6 + src/permission/net_permission.h | 3 + src/permission/permission.cc | 67 ++++++++ src/permission/permission.h | 4 + src/permission/permission_base.h | 3 + src/permission/wasi_permission.cc | 6 + src/permission/wasi_permission.h | 3 + src/permission/worker_permission.cc | 6 + src/permission/worker_permission.h | 3 + .../test-permission-drop-child-process.js | 38 +++++ ...est-permission-drop-diagnostics-channel.js | 34 ++++ test/parallel/test-permission-drop-errors.js | 45 +++++ test/parallel/test-permission-drop-fs-all.js | 38 +++++ .../test-permission-drop-fs-granted-path.js | 160 ++++++++++++++++++ test/parallel/test-permission-drop-fs-read.js | 40 +++++ .../parallel/test-permission-drop-fs-scope.js | 37 ++++ .../test-permission-drop-fs-specific-path.js | 60 +++++++ .../parallel/test-permission-drop-fs-write.js | 32 ++++ test/parallel/test-permission-drop-net.js | 20 +++ .../test-permission-drop-not-enabled.js | 14 ++ test/parallel/test-permission-drop-worker.js | 26 +++ 33 files changed, 879 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-permission-drop-child-process.js create mode 100644 test/parallel/test-permission-drop-diagnostics-channel.js create mode 100644 test/parallel/test-permission-drop-errors.js create mode 100644 test/parallel/test-permission-drop-fs-all.js create mode 100644 test/parallel/test-permission-drop-fs-granted-path.js create mode 100644 test/parallel/test-permission-drop-fs-read.js create mode 100644 test/parallel/test-permission-drop-fs-scope.js create mode 100644 test/parallel/test-permission-drop-fs-specific-path.js create mode 100644 test/parallel/test-permission-drop-fs-write.js create mode 100644 test/parallel/test-permission-drop-net.js create mode 100644 test/parallel/test-permission-drop-not-enabled.js create mode 100644 test/parallel/test-permission-drop-worker.js diff --git a/doc/api/permissions.md b/doc/api/permissions.md index d36590ec3ae9cd..b86eacf1a53f1a 100644 --- a/doc/api/permissions.md +++ b/doc/api/permissions.md @@ -76,7 +76,7 @@ flag. For WASI, use the [`--allow-wasi`][] flag. When enabling the Permission Model through the [`--permission`][] flag a new property `permission` is added to the `process` object. -This property contains one function: +This property contains the following functions: ##### `permission.has(scope[, reference])` @@ -90,6 +90,36 @@ process.permission.has('fs.read'); // true process.permission.has('fs.read', '/home/rafaelgss/protected-folder'); // false ``` +##### `permission.drop(scope[, reference])` + +API call to drop permissions at runtime. This operation is **irreversible**. + +When called without a reference, the entire scope is dropped. When called +with a reference, only the permission for that specific resource is revoked. + +You can only drop the exact resource that was explicitly granted. The +reference passed to `drop()` must match the original grant. If a permission +was granted using a wildcard (`*`), only the entire scope can be dropped +(by calling `drop()` without a reference). If a directory was granted +(e.g. `--allow-fs-read=/my/folder`), you cannot drop individual files +inside it - you must drop the same directory that was originally granted. + +```js +const fs = require('node:fs'); + +// Read config at startup while we still have permission +const config = fs.readFileSync('/etc/myapp/config.json', 'utf8'); + +// Drop read access to /etc/myapp after initialization +process.permission.drop('fs.read', '/etc/myapp'); + +// This will now throw ERR_ACCESS_DENIED +process.permission.has('fs.read', '/etc/myapp/config.json'); // false + +// Drop child process permission entirely +process.permission.drop('child'); +``` + #### File System Permissions The Permission Model, by default, restricts access to the file system through the `node:fs` module. diff --git a/doc/api/process.md b/doc/api/process.md index ed24f30ff5232e..a8c29e890f1ffc 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -3197,6 +3197,65 @@ process.permission.has('fs.read', './README.md'); process.permission.has('fs.read'); ``` +### `process.permission.drop(scope[, reference])` + + + +> Stability: 1.1 - Active Development + +* `scope` {string} +* `reference` {string} + +Drops the specified permission from the current process. This operation is +**irreversible** — once a permission is dropped, it cannot be restored through +any Node.js API. + +If no reference is provided, the entire scope is dropped. For example, +`process.permission.drop('fs.read')` will revoke ALL file system read +permissions. + +When a reference is provided, only the permission for that specific resource +is dropped. For example, `process.permission.drop('fs.read', '/etc/myapp')` +will revoke read access to that directory while keeping other read +permissions intact. + +**Important:** You can only drop the exact resource that was explicitly +granted. The reference passed to `drop()` must match the original grant: + +* If a permission was granted using a wildcard (`*`), such as + `--allow-fs-read=*`, individual paths cannot be dropped - only the entire + scope can be dropped (by calling `drop()` without a reference). +* If a directory was granted (e.g. `--allow-fs-read=/my/folder`), you cannot + drop access to individual files inside it. You must drop the same directory + that was granted. Any remaining grants continue to apply. + +The available scopes are the same as [`process.permission.has()`][]: + +* `fs` - All File System (drops both read and write) +* `fs.read` - File System read operations +* `fs.write` - File System write operations +* `child` - Child process spawning operations +* `worker` - Worker thread spawning operation +* `net` - Network operations +* `inspector` - Inspector operations +* `wasi` - WASI operations +* `addon` - Native addon operations + +```js +const fs = require('node:fs'); + +// Read configuration during startup +const config = fs.readFileSync('/etc/myapp/config.json', 'utf8'); + +// Drop read access to the config directory after initialization +process.permission.drop('fs.read', '/etc/myapp'); + +// This will now throw ERR_ACCESS_DENIED +fs.readFileSync('/etc/myapp/config.json'); +``` + ## `process.pid`