You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce.md
+52Lines changed: 52 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -159,6 +159,51 @@ var proc = fork("a_file.js")
159
159
// This should create the file /tmp/pp2rec
160
160
```
161
161
162
+
## Filesystem-less PP2RCE via `--import` (Node ≥ 19)
163
+
164
+
> [!NOTE]
165
+
> Since **Node.js 19** the CLI flag `--import` can be passed through `NODE_OPTIONS` in the same way `--require` can. In contrast to `--require`, `--import` understands **data-URIs** so the attacker does **not need write access to the file-system** at all. This makes the gadget far more reliable in locked-down or read-only environments.
166
+
>
167
+
> This technique was first publicly documented by PortSwigger research in May 2023 and has since been reproduced in several CTF challenges.
168
+
169
+
The attack is conceptually identical to the `--require /proc/self/*` tricks shown above, but instead of pointing to a file we embed the payload directly in a base64-encoded `data:` URL:
170
+
171
+
```javascript
172
+
const { fork } =require("child_process")
173
+
174
+
// Manual pollution
175
+
b = {}
176
+
177
+
// Javascript that is executed once Node parses the import URL
1.**No disk interaction** – the payload travels entirely inside the process command line and environment.
199
+
2.**Works with ESM-only environments** – `--import` is the canonical way to preload JavaScript in modern Node releases that default to ECMAScript Modules.
200
+
3.**Bypasses some `--require` allow-lists** – a few hardening libraries only filter `--require`, leaving `--import` untouched.
201
+
202
+
> [!WARNING]
203
+
> `--import` support in `NODE_OPTIONS` is still present in the latest **Node 22.2.0** (June 2025). The Node core team is discussing restricting data-URIs in the future, but no mitigation is available at the time of writing.
204
+
205
+
---
206
+
162
207
## DNS Interaction
163
208
164
209
Using the following payloads it's possible to abuse the NODE_OPTIONS env var we have discussed previously and detect if it worked with a DNS interaction:
@@ -716,6 +761,11 @@ At least from v18.4.0 this protection has been **implemented,** and therefore th
716
761
717
762
In [**this commit**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9) the **prototype pollution** of **`contextExtensions`** from the vm library was **also kind of fixed** setting options to **`kEmptyObject`** instead of **`{}`.**
718
763
764
+
> [!INFO]
765
+
> **Node 20 (April 2023) & Node 22 (April 2025)** shipped further hardening: several `child_process` helpers now copy user-supplied `options` with **`CopyOptions()`** instead of using them by reference. This blocks pollution of nested objects such as `stdio`, but **does not protect against the `NODE_OPTIONS` / `--import` tricks** described above – those flags are still accepted via environment variables.
766
+
> A full fix would have to restrict which CLI flags can be propagated from the parent process, which is being tracked in Node Issue #50559.
0 commit comments