RCE in developer mode in nuxt/nuxt
Reported on
Apr 27th 2023
Description
Nuxt contains a test-component-wrapper
component. This is used to mount a single component for testing.
This component has a dynamic import
function which accepts arbitrary user input on the server side. This pattern will almost always lead to an RCE bug.
Requirements & Notes
The server must be running on dev, this does not work in production modes. I'm not entirely sure if this component is included in the production bundle, but this is an incredibly high-risk component. We can use the EMCAScript 'data: import' feature to make payloads easy, this is only possible on nodejs 12+.
Proof of Concept
Start server with pnpm dev
.
Navigate to http://localhost:3000/__nuxt_component_test__/?path=data%3Atext%2Fjavascript%2Cconsole%2Elog%28%22hello%21%22%29%3B
Observe hello!
in output to console.
Other possible exploits
It may be possible to import a gadget from node_modules
or other locations for an exploit if ‘data:’ method is not possible.
Impact
Remote code execution on development servers.
References
Requires dev mode and probably access to local network, changed to complexity High
Fixed in this commit.
Could still be exploitable if:
- Test environment is exposed to the internet
- A parser differential is found where
resolve(query.path)
starts withdevRootDir
but is interpreted differently toimport(query.path)
. This is unlikely to ever be true but could be resolved by changing the code to:
const path = resolve(query.path as string)
if (!path.startsWith(devRootDir)) {
throw new Error(`[nuxt] Cannot access path outside of project root directory: \`${path}\`.`)
}
const comp = await import(/* @vite-ignore */ path as string).then(r => r.default)
An example of this (which doesn't work) would be http:/nuxt/playground/
, if resolve strips the http
part, query.path
now potentially points to a HTTP resource (this does not work by default in node but for arguments sake) while still passing the test.
Seems like this vulnerability affects only > v3.4.0 and < v3.4.2. Indeed, can't reproduced it on v2.15.8. npm registry notifies that all nuxt packages < v3.4.3 has a high vulnerability. Feels wrong, isn't it?
# npm audit report
nuxt <3.4.3
Severity: high
nuxt Code Injection vulnerability - https://github.com/advisories/GHSA-gc34-5v43-h7v8
fix available via `npm audit fix --force`
Will install nuxt@3.5.3, which is a breaking change
node_modules/nuxt
Seems like GHSA-gc34-5v43-h7v8 is incorrect. Should only impact 3.4.0, 3.4.1, 3.4.2
Made changes to GHSA-gc34-5v43-h7v8, waiting for GitHub to merge.
The server being deployed in Development mode is a condition for the vulnerability to work that is well outside the attacker's control.
It is very unlikely an attacker is able to control which mode the server is running in, and will have to be opportunistic to find servers running in this specific mode.