fix(security): path containment checks for Windows environments

- Fixed an issue in extract_path_candidates where shlex.split(posix=True)
  would strip backslashes from Windows paths, mangling UNC paths (e.g. \\server\share)
  before they could be evaluated by _is_windows_absolute.
- Fixed a bypass in validate_path where Windows absolute paths bypassed glob
  expansion and symlink resolution. On Windows, they now fall through to the
  standard Path logic, allowing glob expansion and strict resolution while still
  properly checking containment.
This commit is contained in:
Gracy769 authored and gaebal-gajae committed 2026-10-12 22:05:25 +00:00
1 parent 86428abce6
commit 66d73338bf
1 file changed
+7 -2
+7 -2
View File
@@ -60,7 +60,12 @@ class WorkspacePathScope:
def validate_path(self, candidate: str | Path, cwd: str | Path | None = None) -> PathScopeDecision:
raw = os.path.expandvars(os.path.expanduser(str(candidate)))
if _is_windows_absolute(raw):
return self._validate_windows_path(raw)
if os.name != 'nt':
return self._validate_windows_path(raw)
elif not any(_is_windows_absolute(str(root)) for root in self.roots):
# Even on Windows, deny if no roots are Windows absolute paths (edge case)
return PathScopeDecision(False, 'windows absolute path is outside workspace scope', str(candidate), raw)
base = Path(cwd).expanduser().resolve(strict=False) if cwd else self.roots[0]
path = Path(raw)
if not path.is_absolute():
@@ -116,7 +121,7 @@ def extract_path_candidates(payload: str) -> tuple[str, ...]:
tokens = payload.split()
raw_tokens = payload.split()
candidates: list[str] = []
for token in (*tokens, *raw_tokens):
for token in (*raw_tokens, *tokens):
if not token or token.startswith('-') or _ENV_ASSIGNMENT_RE.match(token):
continue
token = _strip_redirection_operator(token)