T09 · Insecure Skill Coding Practices
- Location
process-file-manager.cjs:25- Finding
Path Traversal Allows Filesystem Writes Outside the Configured Workspace
- Content
View full analysis
Vulnerability Details
File Location:
process-file-manager.cjs:25-29,process-file-manager.cjs:37-48, andprocess-file-manager.cjs:108-110
Vulnerability Type: Unsanitized path construction and directory traversal
Risk Level: MediumVulnerable Code
js const projectDir = path.join(this.baseDir, projectName); // Create project directory fs.mkdirSync(projectDir, { recursive: true });js // Task decomposition location const tasksDir = path.join(projectDir, 'task-decomposition'); fs.mkdirSync(tasksDir, { recursive: true }); this.processFiles.tasks = { json: path.join(tasksDir, 'tasks.json'), markdown: path.join(tasksDir, 'tasks.md'), clawteam: path.join(tasksDir, 'clawteam-tasks.json') }; // Context document location const contextDir = path.join(projectDir, 'context-documents'); fs.mkdirSync(contextDir, { recursive: true });js const report = this.generateProcessFileReport(); const reportPath = path.join(this.baseDir, projectName, 'process-files-report.json'); fs.writeFileSync(reportPath, JSON.stringify(report, null, 2)); return reportPath;Technical Analysis
The
projectNameargument is incorporated directly into filesystem paths without validation, normalization followed by containment verification, or rejection of traversal components. An attacker-controlled value containing sequences such as../can cause the resulting path to escapebaseDir.The affected methods subsequently pass the constructed paths to
fs.mkdirSync()andfs.writeFileSync(). Consequently, this is not merely path disclosure: it provides a concrete filesystem write primitive. The report writer also overwrites an existingprocess-files-report.jsonbecausefs.writeFileSync()uses truncating write behavior by default.The written report content is generated by the application rather than being completely attacker-selected. Nevertheless, the attacker can con ...[truncated 1410 chars]
- Remediation
View remediation
Remediation Suggestions
-
Restrict project names to a conservative allowlist before using them in paths:
js function validateProjectName(projectName) { if ( typeof projectName !== 'string' || !/^[A-Za-z0-9._-]+$/.test(projectName) || projectName === '.' || projectName === '..' ) { throw new Error('Invalid project name'); } } -
Resolve the destination and verify that it remains beneath the configured base directory:
js function resolveWithinBase(baseDir, projectName) { validateProjectName(projectName); const base = path.resolve(baseDir); const destination = path.resolve(base, projectName); if (!destination.startsWith(base + path.sep)) { throw new Error('Project path escapes the configured base directory'); } return destination; } -
Use the verified project directory consistently for every subsequent directory creation and file write. Do not reconstruct the destination from the original untrusted
projectName. -
Reject absolute paths, path separators, null bytes, and
.or..path components explicitly. -
Before writing the report, repeat the containment check on the final resolved file path as defense in depth.
-
If overwriting is unnecessary, use exclusive creation flags such as
{ flag: 'wx' }and return a controlled error when the destination already exists. -
Run the utility with a least-privileged operating-system account and limit write permissions to the intended workspace.
-
Add automated tests covering traversal attempts such as
../target,../../target, mixed separators, encoded separators after upstream decoding, and valid names that share a textual prefix withbaseDir.
-
