Skip to content
5a0c4cbab8e49ac0669d126c854da95e

5a0c4cbab8e49ac0669d126c854da95e

gist.github.com • October 15, 2026

Supplier / product: coderaiser / Cloud Commander (cloudcmd) -

Vulnerability type: CWE-22 path traversal leading to arbitrary file read, with CWE-1188 for the incomplete-fix aspect.

Affected component and code path: server/rest/index.js:130 , inside onGET :

server/root.js exports two siblings. root(dir, rootDir) maps a web path to an OS path through mellow.webToWin , which for a non- / root is path.join(root, current) - and join normalises .. rather than rejecting it. root.resolve(dir, rootDir) wraps the same call and throws Path ... beyond root ...! unless the result is the root or starts with root + separator.

At v19.21.1 there were 13 call sites of root.resolve and exactly one surviving bare root() - the one above. The decoded request path reaches it directly: ponse.getPathName applies querystring.unescape , then /api/v1 , the leading / and the literal pack are stripped, and the remainder is passed in unchecked. streamPack then archives and streams the resolved file back to the caller.

Affected versions: v19.20.2 through v19.21.1. Versions before 19.20.2 are covered by CVE-2026-82460.

Precondition: the operator set --root to something other than / . With the shipped default root: '/' , full-filesystem access is by design and this is not a vulnerability. The route is mounted after authentication(config) ; with the shipped default auth: false no credentials are required.

Impact: arbitrary file read outside the configured --root , returned as a tar.gz or zip the caller downloads. Read-only - streamPack never writes - so this is narrower than CVE-2026-82460, which also covered write/move/copy.

Why this was not a duplicate of CVE-2026-82460: issue #474 listed its sinks verbatim - rename, move, copy, pack (the PUT helper at :289 ) and extract. The onGET call site at :129 appears in neither the issue body nor its , and every hunk of the fix commit b9bdc9ed is inside onPUT /rename/pack/extract. Three sibling routes refused the identical input while GET /api/v1/pack did not; that contrast, not a scanner, was the evidence.

Fixed in v19.21.2 , by converting the one remaining call site to the guard the other sites already used:

server/root.js is unchanged. Call-site census across server/ and common/ : 19.21.1 had root.resolve x13 and one bare root() ; 19.21.2 has x14 and none.

Re-verified at v19.21.2 against a local instance confined with --root : the in-root path still works, the reported request and an absolute-path variant are both refused with Path ... beyond root ... , and five further encodings - including a sibling directory sharing the root's name prefix, which is the case a startsWith guard can get wrong - are also refused.

No exploit code is included here; only what identifies the vulnerability.

Reported through VulnCheck's coordinated disclosure process (CVD case VC-CVD-01330).

Mansurzhan Mavlankulov ( )

Extracted Entities