beam: fix path_sandbox root="/" containment (was requiring "//" prefix)

This commit is contained in:
beam committed 2026-10-28 11:58:49 +00:00
1 parent ec60dedf74
commit 2b080cfca9
1 file changed
+16 -5
+16 -5
View File
@@ -59,13 +59,22 @@ def safe_join(root, *parts):
candidate = os.path.join(rr, *parts) if parts else rr
# normalize (collapses . and redundant slashes) but does not resolve symlinks
candidate = os.path.normpath(candidate)
# containment check on the normalized (pre-symlink) form
if candidate != rr and not candidate.startswith(rr + os.sep):
raise PathEscapeError("joined path escapes root: %r" % candidate)
# containment check on the normalized (pre-symlink) form.
# Special-case root == "/" so we don't require a "//" prefix.
if rr == os.sep:
if not (candidate == rr or candidate.startswith(rr)):
raise PathEscapeError("joined path escapes root: %r" % candidate)
else:
if candidate != rr and not candidate.startswith(rr + os.sep):
raise PathEscapeError("joined path escapes root: %r" % candidate)
# now resolve symlinks and re-check containment
resolved = os.path.realpath(candidate)
if resolved != rr and not resolved.startswith(rr + os.sep):
raise PathEscapeError("symlink escape: %r -> %r" % (candidate, resolved))
if rr == os.sep:
if not (resolved == rr or resolved.startswith(rr)):
raise PathEscapeError("symlink escape: %r -> %r" % (candidate, resolved))
else:
if resolved != rr and not resolved.startswith(rr + os.sep):
raise PathEscapeError("symlink escape: %r -> %r" % (candidate, resolved))
return resolved
@@ -86,4 +95,6 @@ def is_within(root, target):
rt = os.path.realpath(target)
except (OSError, ValueError):
return False
if rr == os.sep:
return rt == rr or rt.startswith(rr)
return rt == rr or rt.startswith(rr + os.sep)