Skip to content

Commit 917f348

Browse files
authored
docs: update security best practices for current threat model (#8374)
* docs: update security best practices for current threat model - Align examples with current SECURITY.md threat model - Add scenarios for malicious deps and prototype pollution - Document Node.js permission model usage - Refresh policy mechanism guidance and external security resources * fixup! docs: update security best practices for current threat model
1 parent 9b189b1 commit 917f348

File tree

1 file changed

+71
-47
lines changed

1 file changed

+71
-47
lines changed

apps/site/pages/en/learn/getting-started/security-best-practices.md

Lines changed: 71 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ guidelines on how to secure a Node.js application.
2626

2727
## Threat List
2828

29+
The Node.js [threat model][] defines what is or is not considered a
30+
_vulnerability in Node.js itself_. Some of the topics below are not
31+
vulnerabilities in Node.js core according to that model, but they are still
32+
important _application-level_ threats that you should account for when building
33+
and operating Node.js software.
34+
2935
### Denial of Service of HTTP server (CWE-400)
3036

3137
This is an attack where the application becomes unavailable for the purpose it
@@ -188,6 +194,13 @@ of requests.
188194

189195
### Malicious Third-Party Modules (CWE-1357)
190196

197+
According to the Node.js [threat model][], scenarios that require a malicious
198+
third-party module are **not** considered vulnerabilities in Node.js core,
199+
because Node.js treats the code it is asked to run (including dependencies)
200+
as trusted. However, malicious or compromised dependencies remain one of the
201+
most critical _application-level_ risks for Node.js users and should be
202+
treated as such.
203+
191204
Currently, in Node.js, any package can access powerful resources such as
192205
network access.
193206
Furthermore, because they also have access to the file system, they can send
@@ -198,9 +211,17 @@ arbitrary code by using `eval()`(or its equivalents).
198211
All code with file system write access may achieve the same thing by writing to
199212
new or existing files that are loaded.
200213

201-
Node.js has an experimental[¹][experimental-features]
202-
[policy mechanism][] to declare the loaded resource as untrusted or trusted.
203-
However, this policy is not enabled by default.
214+
**Examples**
215+
216+
- An attacker compromises the maintainer account of a popular logging library
217+
and ships a new minor version that exfiltrates environment variables
218+
(for example, database passwords or access tokens) to a remote server when
219+
the logger is initialized.
220+
- A typosquatting package with a name similar to a well-known framework is
221+
published to the npm registry. When installed, it runs a postinstall script
222+
that sends SSH keys from the developer's machine to an attacker-controlled
223+
endpoint.
224+
204225
Be sure to pin dependency versions and run automatic checks for vulnerabilities
205226
using common workflows or npm scripts.
206227
Before installing a package make sure that this package is maintained and
@@ -314,6 +335,13 @@ be replaced.
314335

315336
### Prototype Pollution Attacks (CWE-1321)
316337

338+
Per the Node.js [threat model][], prototype pollution that relies on an
339+
attacker controlling user input is **not** considered a vulnerability in
340+
Node.js core, because Node.js trusts the inputs provided by application code.
341+
Nonetheless, prototype pollution is a serious class of vulnerabilities for
342+
Node.js applications and third-party libraries, and you should implement
343+
defenses at the application and dependency level.
344+
317345
Prototype pollution refers to the possibility of modifying or injecting properties
318346
into Javascript language items by abusing the usage of \_\_proto\__,
319347
\_constructor_, _prototype_, and other properties inherited from built-in
@@ -342,6 +370,17 @@ language.
342370
- [CVE-2022-21824][] (Node.js)
343371
- [CVE-2018-3721][] (3rd Party library: Lodash)
344372

373+
Additional scenarios include:
374+
375+
- A web API merges untrusted JSON request bodies into a shared configuration
376+
object without validation. By sending a payload with a `__proto__` property,
377+
an attacker adds unexpected properties to many objects in the process,
378+
leading to logic bugs or denial of service.
379+
- A template rendering service accepts user-controlled options and passes them
380+
directly into a deep merge utility. By polluting `Object.prototype`, an
381+
attacker causes all future templates to behave unexpectedly, potentially
382+
bypassing security checks that rely on object property presence.
383+
345384
**Mitigations**
346385

347386
- Avoid [insecure recursive merges][], see [CVE-2018-16487][].
@@ -355,6 +394,13 @@ language.
355394

356395
### Uncontrolled Search Path Element (CWE-427)
357396

397+
The Node.js [threat model][] considers the file system in the environment
398+
accessible to Node.js as trusted. As a result, issues that rely solely on
399+
controlling files in those locations are **not** considered vulnerabilities in
400+
Node.js core. They are, however, relevant to the security of your overall
401+
deployment and supply chain, so you should harden your environment and use
402+
the mechanisms below to reduce risk.
403+
358404
Node.js loads modules following the [Module Resolution Algorithm][].
359405
Therefore, it assumes the directory in which a module is requested
360406
(require) is trusted.
@@ -370,53 +416,28 @@ Assuming the following directory structure:
370416
If server.js uses `require('./auth')` it will follow the module resolution
371417
algorithm and load _auth_ instead of _auth.js_.
372418

373-
**Mitigations**
419+
## Node.js Permission Model
374420

375-
Using the experimental[¹][experimental-features]
376-
[policy mechanism with integrity checking][] can avoid the above threat.
377-
For the directory described above, one can use the following `policy.json`
378-
379-
```json
380-
{
381-
"resources": {
382-
"./app/auth.js": {
383-
"integrity": "sha256-iuGZ6SFVFpMuHUcJciQTIKpIyaQVigMZlvg9Lx66HV8="
384-
},
385-
"./app/server.js": {
386-
"dependencies": {
387-
"./auth": "./app/auth.js"
388-
},
389-
"integrity": "sha256-NPtLCQ0ntPPWgfVEgX46ryTNpdvTWdQPoZO3kHo0bKI="
390-
}
391-
}
392-
}
393-
```
421+
Node.js provides a **permission model**
422+
that can be used to restrict what a given process is allowed to do at runtime.
423+
This model complements the Node.js [threat model][].
394424

395-
Therefore, when requiring the _auth_ module, the system will validate the
396-
integrity and throw an error if doesn’t match the expected one.
425+
When enabled (for example, using the `--permission` flag), the
426+
permission model lets you selectively allow or deny access to sensitive
427+
capabilities such as:
397428

398-
```console
399-
» node --experimental-policy=policy.json app/server.js
400-
node:internal/policy/sri:65
401-
throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex);
402-
^
403-
404-
SyntaxError [ERR_SRI_PARSE]: Subresource Integrity string "sha256-iuGZ6SFVFpMuHUcJciQTIKpIyaQVigMZlvg9Lx66HV8=%" had an unexpected "%" at position 51
405-
at new NodeError (node:internal/errors:393:5)
406-
at Object.parse (node:internal/policy/sri:65:13)
407-
at processEntry (node:internal/policy/manifest:581:38)
408-
at Manifest.assertIntegrity (node:internal/policy/manifest:588:32)
409-
at Module._compile (node:internal/modules/cjs/loader:1119:21)
410-
at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
411-
at Module.load (node:internal/modules/cjs/loader:1037:32)
412-
at Module._load (node:internal/modules/cjs/loader:878:12)
413-
at Module.require (node:internal/modules/cjs/loader:1061:19)
414-
at require (node:internal/modules/cjs/helpers:99:18) {
415-
code: 'ERR_SRI_PARSE'
416-
}
417-
```
429+
- File system reads and writes.
430+
- Network access (inbound and outbound).
431+
- Child process creation.
432+
- Use of native addons and other powerful APIs.
433+
434+
This can help contain the impact of malicious or compromised dependencies,
435+
untrusted configuration, or unexpected behavior in your own code, since even
436+
trusted code will be prevented from performing actions outside the permissions
437+
you have explicitly granted.
418438

419-
Note, it's always recommended the use of `--policy-integrity` to avoid policy mutations.
439+
Refer to the [Node.js permissions documentation][] for up-to-date flags and
440+
options.
420441

421442
## Experimental Features in Production
422443

@@ -431,6 +452,8 @@ The [OpenSSF][] is leading several initiatives that can be very useful, especial
431452
- [OpenSSF Scorecard][] Scorecard evaluates open source projects using a series of automated security risk checks. You can use it to proactively assess vulnerabilities and dependencies in your code base and make informed decisions about accepting vulnerabilities.
432453
- [OpenSSF Best Practices Badge Program][] Projects can voluntarily self-certify by describing how they comply with each best practice. This will generate a badge that can be added to the project.
433454

455+
You can also collaborate with other projects and security experts through the [OpenJS Security Collaboration Space][].
456+
434457
[threat model]: https://github.com/nodejs/node/security/policy#the-nodejs-threat-model
435458
[security guidance issue]: https://github.com/nodejs/security-wg/issues/488
436459
[nodejs guideline]: https://github.com/goldbergyoni/nodebestpractices
@@ -445,6 +468,7 @@ The [OpenSSF][] is leading several initiatives that can be very useful, especial
445468
[unpublish the package]: https://docs.npmjs.com/unpublishing-packages-from-the-registry
446469
[CWE-444]: https://cwe.mitre.org/data/definitions/444.html
447470
[RFC7230]: https://datatracker.ietf.org/doc/html/rfc7230#section-3
471+
[Node.js permissions documentation]: https://nodejs.org/api/permissions.html#permission-model
448472
[policy mechanism]: https://nodejs.org/api/permissions.html#policies
449473
[typosquatting]: https://en.wikipedia.org/wiki/Typosquatting
450474
[Mitigations for lockfile poisoning]: https://blog.ulisesgascon.com/lockfile-posioned
@@ -457,9 +481,9 @@ The [OpenSSF][] is leading several initiatives that can be very useful, especial
457481
[CVE-2018-16487]: https://www.cve.org/CVERecord?id=CVE-2018-16487
458482
[scrypt]: https://nodejs.org/api/crypto.html#cryptoscryptpassword-salt-keylen-options-callback
459483
[Module Resolution Algorithm]: https://nodejs.org/api/modules.html#modules_all_together
460-
[policy mechanism with integrity checking]: https://nodejs.org/api/permissions.html#integrity-checks
461484
[experimental-features]: #experimental-features-in-production
462485
[`Socket`]: https://socket.dev/
463486
[OpenSSF]: https://openssf.org/
464487
[OpenSSF Scorecard]: https://securityscorecards.dev/
465488
[OpenSSF Best Practices Badge Program]: https://bestpractices.coreinfrastructure.org/en
489+
[OpenJS Security Collaboration Space]: https://github.com/openjs-foundation/security-collab-space

0 commit comments

Comments
 (0)