T09 · Insecure Skill Coding Practices
Error
- Location
- index.js:58
- Finding
- Caller-Controlled Output Path Allows Arbitrary File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `index.js`, lines 58-65 and 151-155 **Vulnerability Type**: Path traversal and arbitrary file overwrite **Risk Level**: High ### Vulnerable Code ```javascript const { start, end, profile = 'trekking', originLabel, destinationLabel, outputDir = path.resolve(process.cwd(), 'routes'), fileName, } = options; ``` ```javascript const finalFileName = fileName || defaultFileName; const outputPath = path.resolve(outputDir, finalFileName); await fs.promises.mkdir(path.dirname(outputPath), { recursive: true }); await fs.promises.writeFile(outputPath, gpxText, 'utf8'); ``` ### Technical Analysis The caller can directly control both `outputDir` and `fileName`. The code resolves these values into an absolute path without verifying that the resulting path remains inside the intended `routes` directory. A `fileName` containing parent-directory traversal sequences such as `../../target` can escape the output directory. An absolute `fileName` can also cause `path.resolve()` to discard the preceding output directory. A caller-controlled absolute `outputDir` provides another direct way to select an arbitrary destination. The destination directory is recursively created, and `fs.promises.writeFile()` overwrites an existing file by default. The content written to the selected path is the GPX response received from the routing server. Exploitation is limited by the operating-system permissions of the Node.js process, but no application-level path boundary is enforced. ### Attack Path 1. An attacker gains the ability to invoke `run()` or influence its `options` object. 2. The attacker supplies a traversal or absolute path through `fileName` or `outputDir`. 3. The Skill requests route data from the remote routing service. 4. `path.resolve()` produces a destination outside the intended `routes` directory. 5. The code recursively creates missing parent directories where permitted. 6. `writeFile()` creates or ove ...[truncated 710 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Remove caller control over `outputDir` unless it is strictly required. - Store generated files beneath a single trusted directory selected by the application. - Permit only a basename for `fileName`; reject absolute paths, path separators, `.` segments, and `..` segments. - Resolve the candidate path and verify that it remains beneath the trusted directory: ```javascript const trustedRoot = path.resolve(process.cwd(), 'routes'); const safeName = path.basename(fileName || defaultFileName); const outputPath = path.resolve(trustedRoot, safeName); const relative = path.relative(trustedRoot, outputPath); if (relative.startsWith('..') || path.isAbsolute(relative)) { throw new Error('Invalid output path'); } ``` - Use an allowlist for filename characters and enforce the `.gpx` extension. - If overwriting is unnecessary, write with the exclusive `wx` flag. - Run the Skill under a dedicated, minimally privileged account with write access limited to the route directory. - Consider defenses against symbolic-link attacks if the output directory may be modified by untrusted local users. ]]>
