T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- index.js:97
- Finding
- Path Traversal in the Video Download Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `index.js`, lines 97-104 **Vulnerability Type**: Unrestricted filesystem path construction **Risk Level**: High ### Vulnerable Code ```js app.get('/download/:id.mp4', (req, res) => { const filePath = path.join(__dirname, 'outputs', `${req.params.id}.mp4`); if (fs.existsSync(filePath)) { res.download(filePath); } else { res.status(404).send('Video not found'); } }); ``` ### Technical Analysis The `id` route parameter is inserted directly into a local filesystem path. The application does not verify that the value is a UUID, reject path separators, or confirm that the resolved path remains inside the intended `outputs` directory. Because route parameters are URL-decoded, a value containing encoded traversal sequences and path separators may cause `path.join()` to resolve a path outside `outputs`. The application then checks the attacker-selected path with `fs.existsSync()` and returns it with `res.download()`. The route always appends `.mp4`, so exploitation is limited to accessible files whose resulting path ends with that extension. This restriction reduces scope but does not prevent unauthorized access to media or other files using that extension. ### Attack Path 1. The attacker identifies the unauthenticated `/download/:id.mp4` endpoint. 2. The attacker supplies encoded `..` segments and path separators as the `id` parameter. 3. Express decodes the route parameter. 4. `path.join(__dirname, 'outputs', ...)` normalizes the traversal sequences and may produce a path outside the `outputs` directory. 5. If the resulting `.mp4` file exists and is readable by the Node.js process, `res.download()` returns it to the attacker. ### Impact Assessment A remote unauthenticated attacker may download files outside the intended output directory when: - The target path resolves to an existing file ending in `.mp4`. - The Node.js process has permission to read the target file. The vulnerability vi ...[truncated 225 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Validate `id` against the exact format generated by the application. For example, require a canonical UUID: ```js const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; app.get('/download/:id.mp4', (req, res) => { if (!UUID_RE.test(req.params.id)) { return res.status(400).send('Invalid video identifier'); } const outputRoot = path.resolve(__dirname, 'outputs'); const filePath = path.resolve(outputRoot, `${req.params.id}.mp4`); if (!filePath.startsWith(`${outputRoot}${path.sep}`)) { return res.status(400).send('Invalid video identifier'); } res.download(filePath, (error) => { if (error && !res.headersSent) { res.status(error.statusCode === 404 ? 404 : 500).send('Unable to download video'); } }); }); ``` 2. Store generated IDs and corresponding server-controlled paths in a database or lookup table rather than deriving arbitrary paths from request parameters. 3. Apply authorization checks so that only the owner of a generated video can download it. 4. Run the service under a dedicated account with read access limited to application-owned directories. 5. Add automated tests using encoded traversal sequences, mixed separators, malformed UUIDs, and nonexistent identifiers. ]]>
