Skip to main content
NRG Sentinel enforces a default-deny policy: every privileged operation is blocked for every third-party package unless an explicit grant is present in settings.js. Capabilities are the unit of that grant.

How capability strings are structured

Every capability follows the Entity:sub-resource:operation naming scheme:
node:credentials:read
fs:write
events:listen:flows:started
network:http
process:env:read
  • Entity — the top-level resource group (node, fs, network, etc.)
  • Sub-resource — narrows the entity to a specific surface (credentials, env, wires)
  • Operation — the action being gated (read, write, delete, execute)
Not every capability has all three segments. fs:read has two; node:credentials:read has three; vm:execute has two. Shorthands exist at each level. node:credentials expands to node:credentials:read + node:credentials:write + node:credentials:delete. The resolver is single-level — nested shorthands must be listed explicitly in parent expansions.

How Sentinel identifies the calling package

Sentinel walks the call stack at runtime and extracts the node_modules/<package> segment from the nearest frame that does not belong to Node-RED or Sentinel itself. The match is against the npm package name exactly as it appears on disk.
fs.readFileSync          ← built-in (skipped)
node-red-contrib-my-node/index.js:42   ← nearest userDir frame → package name extracted here
@node-red/runtime/lib/...              ← Node-RED internal (skipped)
The resolved package name is then looked up in the grants map.

Blocked operation warning format

When Sentinel blocks a call, it logs the following to the Node-RED console:
[@allanoricil/nrg-sentinel] BLOCKED fs.readFileSync() — my-custom-node lacks fs:read
  Call stack:
    at Object.<anonymous> (/data/node_modules/my-custom-node/index.js:42:5)
  To allow, add to settings.js:
    sentinel: { allow: { "my-custom-node": ["fs:read"] } }
For modules blocked entirely at require() time (like vm and worker_threads), the operation throws immediately:
[@allanoricil/nrg-sentinel] BLOCKED require('vm') — my-custom-node lacks vm:execute
The all shorthand grants every capability in this document — including vm:execute and threads:spawn, which escape Sentinel’s Module._load hook coverage entirely. Never use all in a production permissions file.

Capability groups

node:*

What a package can do to node objects in the runtime

flows:*

What a package can do to the deployed flow graph

network:*

What outbound network calls a package can make

fs:*

What file system operations a package can perform

process:*

What OS-level operations a package can perform

hooks:*

What message pipeline hooks a package can register

http:*

What HTTP routes and middleware a package can register

events:*

What a package can listen to or emit on the internal event bus

registry:*

What a package can do to the node type registry

settings:*

What a package can do to the runtime settings object

storage:*

What a package can do to the persistent storage layer

vm:*, threads:*, comms:*

VM contexts, worker threads, and the comms channel

All capability groups at a glance

GroupWhat it gates
nodeOperations on live node objects obtained via RED.nodes.getNode()
flowsReading, writing, and deploying the flow graph via RED.runtime.flows.*
networkOutbound HTTP, fetch, raw TCP/UDP sockets, DNS lookups, and inbound listeners
fsFile system reads and writes via require('fs') and its variants
processChild process execution, process.env access, and process.exit()
hooksMessage pipeline hook registration via RED.hooks.add() and .remove()
httpRoute and middleware registration on the admin and node Express instances
eventsListening to and emitting on the RED.events internal event bus
registryNode type registration and lookup via RED.nodes.registerType() / getType()
settingsReading and writing RED.settings keys
storageDirect access to the persistence layer via RED.runtime.storage.*
vmRunning code in isolated V8 contexts via require('vm')
threadsSpawning worker threads via require('worker_threads')
commsPublishing to the server-to-editor WebSocket channel via RED.comms.publish()

Build docs developers (and LLMs) love