Node.js 25 permission model: scope --allow-net and --allow-fs for production (2026)

Node 25 added --allow-net to the permission model. Here is how to scope file, network and process access to harden production Node.js servers in 2026.

Read time
13 min
Word count
2K
Sections
12
FAQs
8
Share
Node.js permission model hardening concept with padlock and shield motifs
Node.js secure-by-default: scoping the permission model in production.
On this page · 12 sections
  1. Why the permission model matters in 2026
  2. What the permission model is, and what it is not
  3. The flags you actually use
  4. Using --permission-audit before you enforce
  5. The version trap: --allow-net is not in Node 24 LTS
  6. Checking permissions at runtime
  7. Where the model still needs help
  8. India-specific considerations
  9. A short rollout checklist
  10. FAQ
  11. How eCorpIT can help
  12. References

Summary. Node.js added a process permission model in v20.0.0 (April 2023), and Node.js 25.0.0, released on 15 October 2025, extended it with --allow-net so network access can be denied by default. That matters because 2026 has been a brutal year for the npm registry: attackers pushed malicious versions of axios (over 100 million weekly downloads) on 31 March 2026, of node-ipc (over 10 million weekly downloads) on 14 May 2026, and a wave of typosquatted packages documented by Microsoft on 28 May 2026 that scraped cloud and CI/CD secrets. Most of those payloads did one thing: read local secrets and phone home. With --permission --allow-fs-read and --allow-net scoped tightly, a hijacked dependency cannot quietly open ~/.aws/credentials or reach a command-and-control server. IBM's 2025 Cost of a Data Breach report put the global average breach at USD 4.44 million, down 9% year on year, so narrowing what your runtime is allowed to touch is cheap insurance. This guide covers the flags, the production invocation, the --permission-audit workflow, and the version trap that catches teams on Node 24 LTS.

Why the permission model matters in 2026

The threat has moved from your code to your dependencies. A modern Node.js service pulls in hundreds of transitive packages, and each one runs with the full authority of the process: it can read any file the user can read, open outbound sockets, and spawn child processes. For years that was accepted as the cost of the ecosystem. In 2026 the bill came due.

The pattern in every major incident this year is the same. An attacker compromises a maintainer account or typosquats a popular name, publishes a version with a post-install or import-time payload, and the payload harvests credentials before anyone notices. Palo Alto's Unit 42 has tracked a steady run of these through the year. Microsoft's security team documented typosquatted npm packages in May 2026 that scraped cloud and CI/CD secrets from AWS, Azure, GCP and Kubernetes environments and shipped them to an external server.

npm incident (2026) Date Scale What the payload targeted
axios maintainer hijack 31 Mar 2026 100M+ weekly downloads Credential and token exfiltration
node-ipc malicious versions 14 May 2026 10M+ weekly downloads Local developer secrets
Typosquat campaign (Microsoft) 28 May 2026 Multiple typosquats AWS, Azure, GCP, Kubernetes secrets
Jscrambler packages (Rescana) Jul 2026 Coordinated set Credential theft

Read that table as an operations problem, not a news feed. Every one of those payloads needed two capabilities to succeed: file system read to find the secret, and network access to send it out. The permission model exists to take those capabilities away unless you grant them.

What the permission model is, and what it is not

The Node.js permission model is a process-level allow-list. You start the runtime with --permission, and from that point file system, network, child-process, worker and native-addon access are denied unless you explicitly grant them. The Node.js documentation calls it a "seat belt": it stops trusted code from doing things it was never meant to do.

Be honest about the boundary. Node's own security policy states that the runtime trusts any code it is asked to run, and the permission model documentation says plainly that it "does not provide security guarantees in the presence of malicious code." Determined malware with the right primitives can attempt to escape it. So the model is not a sandbox and not a replacement for vetting dependencies. What it does is narrow the blast radius and raise the cost of an attack: a credential-stealer that cannot open a socket is a far smaller problem than one that can.

Rafael Gonzaga, the Node.js Technical Steering Committee member who cut the release, framed the direction in the Node.js 25.0.0 announcement: "This release doubles down on secure-by-default apps and web-standard APIs: the permission model gains --allow-net, Web Storage is enabled by default, and ErrorEvent is now a global." The --allow-net addition is the piece that makes the model useful for a network service, because before it, turning the model on either blocked all networking or required workarounds.

The flags you actually use

Enable the model with --permission (the flag was called --experimental-permission before the feature stopped being experimental). Everything else is a grant. The important ones for a backend service:

Flag Controls Example
--permission Turns the model on; denies by default node --permission app.js
--allow-fs-read File system reads, scoped to paths --allow-fs-read=/app
--allow-fs-write File system writes, scoped to paths --allow-fs-write=/app/tmp
--allow-net Network access (added in v25.0.0) --allow-net
--allow-child-process child_process spawning --allow-child-process
--allow-worker Worker threads --allow-worker
--allow-addons Native C++ addons --allow-addons

File system flags take path arguments and glob patterns, so you grant the narrowest tree the service needs rather than the whole disk. A typical production invocation for an HTTP API that reads its code from /app, writes only to a temp directory, and talks to the network looks like this:


            node \
  --permission \
  --allow-fs-read=/app \
  --allow-fs-write=/app/var \
  --allow-net \
  server.js
          

Anything the process was not granted throws ERR_ACCESS_DENIED at the point of use. If a compromised dependency tries to read /home/app/.ssh/id_ed25519, the read fails because that path is outside the --allow-fs-read grant. That is the whole point: the service keeps working, the exfiltration does not.

Note what is missing from that command. There is no --allow-child-process and no --allow-addons. Most web services never legitimately spawn a shell or load a native addon at runtime, so leaving those denied removes two of the most common escalation paths in one stroke. If your service genuinely needs to shell out, grant it and treat that grant as a code smell worth reviewing.

Using --permission-audit before you enforce

The reason teams avoid least-privilege flags is fear of breaking production. The permission model answers that with an audit mode. The --permission-audit flag, added in the Node 25 line, runs every permission check but, instead of throwing ERR_ACCESS_DENIED, emits a warning for each violation. You learn exactly what your application touches without denying anything.

The rollout that works in practice is three steps. First, run your full test suite and a soak period in staging under audit:


            node --permission --permission-audit server.js
          

Second, collect the warnings. Each one names a scope and a reference, for example a file path the app read or a network call it made. That list is the real permission manifest of your service, derived from behaviour rather than guesswork. Third, translate the manifest into explicit --allow-* grants, remove --permission-audit, and redeploy in enforcing mode. From then on, any new capability a dependency tries to use shows up as a failed request in a controlled place instead of a silent secret leak.

This is also the cleanest way to catch a supply-chain change after the fact. If a routine dependency bump suddenly makes your service attempt an outbound connection it never made before, audit mode surfaces it in staging rather than production.

The version trap: --allow-net is not in Node 24 LTS

Here is the detail that catches teams. --allow-net landed in Node.js 25.0.0 as a semver-major change. It was not backported. Node 25 is an odd-numbered "Current" release with a short support window, and most production fleets run on an even-numbered Long Term Support line. As of July 2026 the latest LTS is the Node 24 line (24.18.0), and Node 24 does not have --allow-net. Node 26 is the current release (26.5.0) and does include it, and Node 26 is the line expected to become the next Active LTS under Node's even-numbered release schedule.

Node.js line --allow-net available Role in production (Jul 2026)
Node 22 No Maintenance LTS
Node 24 No Active LTS, latest 24.18.0
Node 25 Yes (added 25.0.0) Current, short-lived, not LTS
Node 26 Yes Current 26.5.0, next Active LTS line

The practical read for a CTO: if network-scoped permissions are part of your hardening plan, your target is Node 26 LTS, and the window to test it is now, on the current 26.x release, before it becomes the default LTS line. Running on Node 24 today, you can still use --permission with file system, child-process and worker grants; you just cannot scope the network yet, so keep egress control at the container or VPC layer until you move. If you are still planning that jump, our Bun vs Node.js backend runtime decision guide covers the runtime trade-offs, and the Node.js security release patch-response playbook covers how to keep any line patched.

Checking permissions at runtime

The model also exposes a runtime API, process.permission, so code can ask what it is allowed to do before it tries. This is useful for graceful degradation: a service can check for a capability and log a clear startup error rather than failing deep inside a request.


            if (!process.permission.has('fs.read', '/app/config')) {
  throw new Error('Missing fs.read grant for /app/config; check startup flags');
}

// Narrow a worker's own authority further at runtime
process.permission.has('net'); // false when started without --allow-net
          

Combined with startup checks, this turns permission configuration into something you can assert in tests. A small integration test that boots the server under --permission with the intended grants and confirms process.permission.has(...) returns the expected values will catch a misconfigured deployment before it ships.

Where the model still needs help

Least privilege at the process level is one layer, not the whole answer. Three limits are worth stating clearly.

First, --allow-net is coarse. In its current form it is closer to an on/off switch for networking than a per-host allow-list, and Node's 2026 security releases have been tightening edge cases, including applying network permission checks to Unix domain socket connections. Until fine-grained host scoping is dependable, keep an egress firewall or service-mesh policy in front of the service so a granted network permission still cannot reach an arbitrary destination.

Second, the model does not vet packages. It contains a bad package's actions; it does not stop you installing one. Signature verification, provenance and lockfile discipline still matter. Trusted publishing with OIDC is the complementary control here, covered in our npm OIDC trusted publishing hardening guide.

Third, the model protects the runtime, not the build. Post-install scripts during npm install run in your CI environment, often with more secrets in scope than production. Harden the pipeline separately, and treat the permission model as the last line inside the running container, part of the wider Interop 2026 web platform guide baseline for modern backends.

India-specific considerations

For teams building under India's Digital Personal Data Protection Act 2023 (DPDP), the permission model maps neatly onto a compliance argument. DPDP expects data fiduciaries to apply reasonable security safeguards and to limit access to personal data. A Node.js service that runs under --permission with a --allow-fs-read grant scoped to its own application tree can show, concretely, that the runtime cannot read arbitrary user data on the host. That is a stronger control statement than a policy document, and it is the kind of technical safeguard auditors respond to.

The same reasoning applies to lenders and fintechs under RBI expectations and to any organisation that processes health or payment data. Scoping file and network access does not make a service DPDP compliant on its own, but it is a low-cost, demonstrable safeguard that fits the least-privilege principle regulators keep returning to. Design the grants once, assert them in tests, and they hold across every deploy.

A short rollout checklist

Turning this into a plan rather than a demo takes five moves. Confirm your target Node line and whether it has --allow-net. Run the service under --permission --permission-audit in staging through a full test cycle. Convert the audit warnings into explicit --allow-fs-read, --allow-fs-write and, where available, --allow-net grants. Add a startup assertion using process.permission.has(...) so a bad config fails loudly. Keep container-level egress and CI hardening in place, because the runtime model is one layer of several. Done in that order, the change is boring, which is exactly what a security change should be.

FAQ

How eCorpIT can help

eCorpIT is a Gurugram-based engineering organisation, ISO 27001:2022 certified and assessed at CMMI Level 5, and we harden Node.js services for production as part of our backend and platform work. We map your service's real file, network and process needs under --permission-audit, convert them into scoped grants, add startup assertions, and layer them with CI and egress controls so the change is safe to ship. If a dependency incident has you reviewing your runtime posture, our software supply chain security service and secure development and AppSec service cover the full picture. Talk to our senior engineering team at /contact-us/.

References

  1. Node.js 25.0.0 release announcement — Node.js, 15 October 2025 (adds --allow-net, V8 14.1, Web Storage by default).
  1. Permissions — Node.js v26.5.0 documentation — permission model, flags and runtime API.
  1. Node.js March 2026 security releases — network permission checks for Unix domain sockets.
  1. Axios npm package compromised — Trend Micro, March 2026.
  1. Malicious node-ipc versions published to npm — StepSecurity, May 2026.
  1. Typosquatted npm packages used to steal cloud and CI/CD secrets — Microsoft Security Blog, 28 May 2026.
  1. Monitoring npm supply chain attacks — Palo Alto Networks Unit 42, updated July 2026.
  1. Jscrambler npm packages compromised — Rescana, July 2026.
  1. Cost of a Data Breach 2025 — IBM, global average USD 4.44 million.
  1. Node.js 20 new permission model — InfoQ, April 2023.
  1. Node.js Security Policy (SECURITY.md) — the runtime trusts code it is asked to run.

_Last updated: 29 July 2026._

Frequently asked

Quick answers.

01 What does the Node.js permission model actually protect against?
It stops trusted code, including your dependencies, from taking actions you did not grant, such as reading files outside a set path or opening network connections. Node's documentation calls it a seat belt. It narrows the blast radius of a compromised package but is not a sandbox against deliberately malicious code.
02 Which Node.js version added --allow-net?
Node.js 25.0.0 added --allow-net, released on 15 October 2025 as a semver-major change. It was not backported to Node 24. The current Node 26 line includes it, and Node 26 is the next Active LTS line, so a production-ready network-scoped setup targets it.
03 Can I use the permission model on Node 24 LTS today?
Yes, partly. Node 24, the Active LTS as of July 2026, supports --permission with --allow-fs-read, --allow-fs-write, --allow-child-process and --allow-worker. It does not have --allow-net, so you cannot scope network access at the runtime yet. Handle egress control at the container or network layer until you move to Node 26.
04 What is --permission-audit for?
It runs every permission check but emits a warning instead of throwing ERR_ACCESS_DENIED. You start your service under --permission --permission-audit in staging, collect the warnings to see exactly what the app touches, then convert that list into explicit grants before enforcing. It removes the fear of breaking production while adopting least privilege.
05 Does the permission model stop npm supply-chain attacks?
It reduces their impact rather than preventing installation. The 2026 attacks on axios, node-ipc and others relied on reading local secrets and sending them out. A service without --allow-net and with a narrow --allow-fs-read grant denies both actions, so a hijacked dependency cannot exfiltrate. Package vetting and provenance remain separate, necessary controls.
06 Is --allow-net a per-host allow-list?
Not yet in a dependable form. In its current shape --allow-net behaves closer to an on or off switch for networking than a fine-grained per-destination policy, and 2026 security releases have been tightening related edge cases such as Unix domain sockets. Keep an egress firewall or service-mesh policy in front of the service for host-level control.
07 Does turning on --permission slow the application down?
The checks are lightweight and happen at the point of resource access, so the runtime overhead is minor for typical web workloads. The real cost is engineering time to map the correct grants, which the --permission-audit workflow largely automates. Most teams find the operational risk sits in misconfiguration, not performance.
08 How does this help with DPDP or RBI compliance?
It provides a demonstrable least-privilege safeguard. A Node.js service scoped so its runtime cannot read personal data outside its own tree gives auditors a concrete technical control, not just a policy statement. It does not make a system compliant by itself, but it fits the access-limitation principle that DPDP and RBI security expectations both emphasise.

About the author

Manu Shukla

Founder & Director

Founder of eCorpIT. Hands-on engineer leading senior-only delivery for AI apps, custom software, and cloud systems for global clients.

Subscribe

One engineering note a week. No fluff, no spam.

Senior-architect playbooks on AI agents, mobile apps, cloud, security, data, and marketing — delivered every Wednesday.

Past the reading

Read enough. Let's build something.

A senior architect responds in 24 working hours with scope, indicative cost, and a timeline. NDA before any technical conversation.