T09 · Insecure Skill Coding Practices
- Location
index.js:35- Finding
Workspace Boundary Bypass Through Symbolic-Link Traversal
- Content
View full analysis
Vulnerability Details
File Location:
index.js, lines 35–39
Vulnerability Type: Unrestricted symbolic-link traversal
Risk Level: Mediumjs const fullPath = path.join(dir, item); const stat = fs.statSync(fullPath); if (stat.isDirectory()) { walkDir(fullPath, stats); } else {Technical Analysis
The recursive scanner uses
fs.statSync(), which follows symbolic links, and does not validate the canonical path of each traversed entry against the configured workspace root. Consequently, a symbolic link located within/home/duan/.openclaw/workspacecan resolve to a directory outside that workspace.Once followed,
walkDir()recursively enumerates the linked directory, whilecountLines()reads accessible files to calculate line counts. The code neither rejects symbolic links throughfs.lstatSync()nor tracks canonical directories already visited. This also permits symbolic-link cycles that can cause unbounded recursion until the process fails.Attack Path
- An attacker gains the ability to add a filesystem entry to the scanned workspace, such as through a cloned or extracted repository.
- The attacker creates a symbolic link inside the workspace that points to an accessible directory outside it.
- A user invokes the Skill through
node index.jsornpm start. fs.statSync()follows the symbolic link and reports the target as a directory.walkDir()recursively enumerates the external target, andcountLines()reads its files.- Aggregate file and line statistics for out-of-scope data are included in program output. If the link creates a directory cycle, recursion may instead exhaust process resources or terminate with an error.
Impact Assessment
Exploitation occurs with the filesystem privileges of the Node.js process; it does not grant additional operating-system privileges. The scanner can read any file reachable through the symbolic link that the invokin ...[truncated 489 chars]
- Remediation
View remediation
Remediation Suggestions
- Use
fs.lstatSync()for each directory entry and reject symbolic links before traversal:js const stat = fs.lstatSync(fullPath); if (stat.isSymbolicLink()) continue; - Canonicalize the workspace root and every candidate path with
fs.realpathSync(). Traverse a path only when it equals the canonical root or begins with the canonical root followed bypath.sep. - Maintain a set of visited canonical directory paths, or device/inode pairs, to prevent cycles and repeated traversal.
- Handle filesystem errors around
readdirSync(),lstatSync(), andrealpathSync()so inaccessible or concurrently removed entries do not terminate the scan. - Consider traversal limits, such as maximum depth, file count, and file size, to reduce denial-of-service risk from hostile repository contents.
- Accept an explicitly selected repository path rather than relying solely on the hardcoded, user-specific workspace path, and document the enforced traversal boundary.
- Use
