Path traversal in unjs/storage leads to code injection due to unsanitzed code generation in unjs/nitro

Valid

Reported on

Jul 27th 2022


Path Traversal

A path traversal vulnerability exists within unjs/unstorage when using the file system storage driver.

This vulnerability can be exploited when the user has control over the key name. By creating key names containing sequences of ../ or ..: we can navigate the file system.

We are able to use : as a substitute to / due to this line.

Static Code Injection

When generating production builds, nitro bundles assets, here is an example of this output:

const _assets = {
  ['server:whatever.json']: {
    import: // ...
    meta: // ...
  }
};

The filename in this output is not sanitized, this allows us to output code in the final bundle by using specially crafted file names.

For example, a file called ' + (()=>{console.log('hacked');return ''})() + ' will produce the following output.

const _assets = {
  ['server:' + (()=>{console.log('hacked');return ''})() + '.json']: {
    import: // ...
    meta: // ...
  }
};

(the same issue exists within the import statement, but it has been omitted to keep it simple.)

It is important to note that we MUST generate valid code, or the build will fail.

Path Traversal In Nitro

When using a cached event handler in Nitro in development mode, a json file is placed on the file system, containing cache information. This path is influenced by the file path in the request.

This can also happen in production mode if the configuration is changed, but file system storage is default for cache in development mode.

In a scenario where there is a cached event handler, on a wildcard path, we can place .json files with arbitary names on the file system by constructing a path prefixed with ..:.

This would happen if:

  • A cached event handler is defined on a [name].ts route or [...].ts route.
  • SWR is applied to a [name].ts route or [...].ts route. (caching api)

Proof of concept

The following must be true for the proof of concept to work.

  1. Target is running a development server on linux.
  2. Target has a cached wildcard event handler.
  3. Target can be influenced to run a production build.

Setup

This is an example of an impacted configuration:

// nitro.config.ts
import { defineNitroConfig } from "nitropack";

export default defineNitroConfig({
    routes: {
        '**': { swr: true }
    }
})

// /routes/[...].ts
export default () => `Wildcard!`

Exploit

  1. Make a request to http://localhost:3000/..:..:..:..:..:assets:' + (()=>{console.log('hacked');return ''})() + 'while running in DEVELOPMENT mode (or convince user to place specially crafted file in assets directory)
  2. Convince, or wait for user to start a production build.
  3. Convince, or wait for user to run production build.
  4. Profit!

Note

Due to the way code generation is done in nitro and nuxt this vulnerability likely occurs in many other places where a specially crafted file name can be placed within the project. This is the only example I could find that doesn't require a user to insert it themself.

Impact

This vulnerability is capable of RCE on target.

We are processing your report and will contact the unjs/nitro team within 24 hours. 2 months ago
OhB00 modified the report
2 months ago
We have contacted a member of the unjs/nitro team and are waiting to hear back 2 months ago
OhB00
2 months ago

Researcher


I've found quite a few different variations of this, none that you can trigger automatically, should I include these in the report ?

We have sent a follow up to the unjs/nitro team. We will try again in 7 days. 2 months ago
OhB00
2 months ago

Researcher


Has been patched in latest commits.

We have sent a second follow up to the unjs/nitro team. We will try again in 10 days. 2 months ago
OhB00
a month ago

Researcher


@admin has been fixed but report not closed https://github.com/unjs/nitro/commit/7aaab6d0262ceb6cd8487fc046eb4f866394cfe9 https://github.com/unjs/unstorage/commit/d628fab73b4cf83758f08817b275a223725714ab

We have sent a third and final follow up to the unjs/nitro team. This report is now considered stale. a month ago
pooya parsa validated this vulnerability a month ago
OhB00 has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
pooya parsa confirmed that a fix has been merged on 7aaab6 a month ago
The fix bounty has been dropped
pooya parsa gave praise a month ago
Thanks for reporting the issue and follow-ups <3
The researcher's credibility has slightly increased as a result of the maintainer's thanks: +1
to join this conversation