From d7706363a381b6d2763bbcc4c4c9e1e09c555812 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 11 Jun 2026 18:52:15 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITIC?= =?UTF-8?q?AL]=20Fix=20Arbitrary=20File=20Write=20via=20symlink=20path=20t?= =?UTF-8?q?raversal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/sentinel.md | 5 +++++ scanner/cli/vibesec.py | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 1e9e764..9ee92e8 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -12,3 +12,8 @@ **Vulnerability:** The `_collect_files` function in `scanner/cli/vibesec.py` used `os.scandir` without explicitly checking if entries were symbolic links before processing them as directories or files. This could allow for arbitrary file read or path traversal vulnerabilities by processing symlinks that point outside the expected directories. **Learning:** During static analysis, directory and file collection methods must be robust against maliciously crafted directory structures, specifically symbolic links pointing to sensitive system files. **Prevention:** Explicitly use `entry.is_symlink()` and check `follow_symlinks=False` on `is_file()` to prevent traversing external links or including them during scan operations. + +## 2026-06-11 - Fix Arbitrary File Write via symlink path traversal in `vibesec init` +**Vulnerability:** The `cmd_init` command in `scanner/cli/vibesec.py` created files and directories inside `.cursor/rules` or `VIBESEC_CHECKLIST.md` in the current project root. However, if the project directory contained malicious symlinks (e.g., `.cursor -> /etc` or `.cursor -> /tmp`), the CLI would unknowingly traverse the symlink and write files (e.g., `vibesec.md`) outside the intended directory. This leads to an Arbitrary File Write vulnerability, potentially allowing attackers to overwrite sensitive files or escalate privileges on the victim's machine. +**Learning:** Even simple CLI file operations (like initializing project configurations) are susceptible to Path Traversal via symlinks. When dealing with directory structures that could be maliciously crafted, we cannot trust that `Path(".").resolve() / ".cursor"` stays within the bounds of `Path(".").resolve()`. +**Prevention:** Before performing any filesystem mutation operations (e.g. `mkdir` or `write_text`), ensure the fully resolved path resides strictly within the expected parent boundary. Use `target_file.resolve().is_relative_to(project_root)` as a security check to detect and abort if the path escapes the intended directory. diff --git a/scanner/cli/vibesec.py b/scanner/cli/vibesec.py index 2931698..ef9fa7c 100644 --- a/scanner/cli/vibesec.py +++ b/scanner/cli/vibesec.py @@ -313,6 +313,12 @@ def cmd_init(args): config = tool_configs[tool] if not config.get("shared_only"): target_file = project_root / config["path"] + + # SECURITY: Prevent Arbitrary File Write via symlink path traversal + if not target_file.resolve().is_relative_to(project_root): + print(f"Error: Target path {target_file} escapes the project root. Aborting.", file=sys.stderr) + sys.exit(1) + target_file.parent.mkdir(parents=True, exist_ok=True) if target_file.is_symlink(): target_file.unlink() @@ -333,6 +339,12 @@ def cmd_init(args): installed.append(str(config["path"])) # Always create the checklist checklist_file = project_root / "VIBESEC_CHECKLIST.md" + + # SECURITY: Prevent Arbitrary File Write via symlink path traversal + if not checklist_file.resolve().is_relative_to(project_root): + print(f"Error: Checklist path {checklist_file} escapes the project root. Aborting.", file=sys.stderr) + sys.exit(1) + if checklist_file.is_symlink(): checklist_file.unlink() if not checklist_file.exists(): From 0fb2cdc19d2b890e58849f644ff47579bd482882 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 12 Jun 2026 03:50:31 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITIC?= =?UTF-8?q?AL]=20Fix=20Arbitrary=20File=20Write=20via=20symlink=20path=20t?= =?UTF-8?q?raversal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 606c41bd21af745113d1e0f9e2dad44ab60e8603 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 12 Jun 2026 23:22:53 +0900 Subject: [PATCH 3/3] Trigger OpenCode review