T09 · Insecure Skill Coding Practices
- Location
src/scanner/api.ts:89- Finding
Arbitrary File Overwrite Through Scanner Filename Traversal
- Content
View full analysis
, skillName?: string, ) { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tork-scan-src-')); try { for (const [filename, content] of Object.entries(files)) { const filePath = path.join(tmpDir, filename); const dir = path.dirname(filePath); fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(filePath, content); } const report = await scanner.scanSkill(tmpDir); if (skillName) { report.skillName = skillName; } return report; } finally { fs.rmSync(tmpDir, { recursive: true, force: true }); } } ``` ### Technical Analysis `scanFromSource()` treats each key in the caller-provided `files` object as a trusted relative filename. It joins that value to the temporary directory but does not reject `..` path components or verify that the normalized destination remains inside `tmpDir`. A filename containing enough parent-directory components can therefore escape the scanner's temporary directory. The function then creates parent directories and calls `fs.writeFileSync()` without exclusive-create or no-follow protections. Existing files writable by the process can consequently be replaced. The cleanup operation only removes `tmpDir`; files written after escaping that directory are not removed. The same vulnerable implementation is present in the distributed JavaScript referenced by the package entry point, so this is not limited to unused TypeScript source. ### Attack Path 1. An application exposes `scanFromSource()` to scan user-supplied source maps. 2. An attacker supplies a filename such as `../../../../path/to/writable-target`. 3. `path.join(tmpDir, filename) ...[truncated 1170 chars]- Remediation
View remediation
