Skip to content

Commit 1a2a9dd

Browse files
committed
Verify real paths in create_safe_path to prevent path traversal
- Update `create_safe_path` to find the deepest existing ancestor of the target path, resolve its `realpath`, and strictly verify it begins with the workspace root's `realpath` plus `path.sep` to prevent symlink escapes. └── apps └── editor └── src ├── commands │ ├── apply-response-command │ │ ├── response-processor │ │ │ ├── handlers │ │ │ │ ├── diff-handler.ts │ │ │ │ ├── fast-replace-handler.ts │ │ │ │ ├── patch-repair-handler.ts │ │ │ │ ├── restore-preview-handler.ts │ │ │ │ ├── search-replace-handler.ts │ │ │ │ └── truncated-handler.ts │ │ │ └── response-processor.ts │ │ └── utils │ │ ├── file-operations │ │ │ ├── apply-file-relocations.ts │ │ │ ├── create-file-if-needed.ts │ │ │ ├── read-rename-source-file.ts │ │ │ ├── relocate-file.ts │ │ │ └── undo-files.ts │ │ └── preview │ │ ├── build-history-files.ts │ │ └── file-preparer.ts │ ├── code-at-cursor-command │ │ └── code-at-cursor-commands.ts │ ├── new-file-command.ts │ ├── new-folder-command.ts │ └── rename-command.ts ├── utils │ ├── normalize-path.ts │ └── path-sanitizer.ts └── views └── prompt └── backend └── message-handlers └── handle-patch-repair.ts
1 parent e40a144 commit 1a2a9dd

1 file changed

Lines changed: 21 additions & 1 deletion

File tree

‎apps/editor/src/utils/path-sanitizer.ts‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const sanitize_file_name = (name: string): string => {
1515
}
1616

1717
const segments = name.split(/[/\\]/)
18-
if (segments.some(seg => seg === '.git')) {
18+
if (segments.some((seg) => seg === '.git')) {
1919
return ''
2020
}
2121

@@ -51,6 +51,26 @@ export const create_safe_path = (
5151

5252
const full_path = path.resolve(resolved_parent, sanitized_name)
5353

54+
let current_path = full_path
55+
while (true) {
56+
try {
57+
const real_path = fs.realpathSync(current_path)
58+
const prefix = resolved_parent.endsWith(path.sep)
59+
? resolved_parent
60+
: resolved_parent + path.sep
61+
if (real_path !== resolved_parent && !real_path.startsWith(prefix)) {
62+
return null
63+
}
64+
break
65+
} catch {
66+
const parent = path.dirname(current_path)
67+
if (parent === current_path) {
68+
break
69+
}
70+
current_path = parent
71+
}
72+
}
73+
5474
const relative_path = path.relative(resolved_parent, full_path)
5575

5676
if (relative_path.startsWith('..') || path.isAbsolute(relative_path)) {

0 commit comments

Comments
 (0)