Skip to content

Commit aaef246

Browse files
committed
fix: prevent path traversal in listWorkspaceDirectory, fix Windows gitignore matching
1 parent 86d977d commit aaef246

File tree

1 file changed

+17
-1
lines changed

1 file changed

+17
-1
lines changed

src/node/services/projectService.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,20 @@ async function listWorkspaceDirectory(
8989
relativePath?: string
9090
): Promise<Result<FileTreeNode[]>> {
9191
try {
92+
// Validate relativePath doesn't escape workspace
93+
if (relativePath) {
94+
// Reject absolute paths
95+
if (path.isAbsolute(relativePath)) {
96+
return Err("Absolute paths are not allowed");
97+
}
98+
// Normalize and verify it stays within workspace
99+
const resolved = path.resolve(workspacePath, relativePath);
100+
const normalizedWorkspace = path.resolve(workspacePath);
101+
if (!resolved.startsWith(normalizedWorkspace + path.sep) && resolved !== normalizedWorkspace) {
102+
return Err("Path traversal not allowed");
103+
}
104+
}
105+
92106
const targetPath = relativePath ? path.join(workspacePath, relativePath) : workspacePath;
93107
const normalizedPath = path.resolve(targetPath);
94108

@@ -102,7 +116,9 @@ async function listWorkspaceDirectory(
102116
.map((entry) => {
103117
const entryPath = relativePath ? path.join(relativePath, entry.name) : entry.name;
104118
// For directories, append / to match gitignore directory patterns
105-
const pathToCheck = entry.isDirectory() ? `${entryPath}/` : entryPath;
119+
// Use POSIX separators for gitignore matching (Windows uses backslashes)
120+
const posixPath = entryPath.split(path.sep).join("/");
121+
const pathToCheck = entry.isDirectory() ? `${posixPath}/` : posixPath;
106122
const ignored = ig ? ig.ignores(pathToCheck) : false;
107123

108124
return {

0 commit comments

Comments
 (0)