diff --git a/src/app_helpers.py b/src/app_helpers.py index 823b01f..8570820 100644 --- a/src/app_helpers.py +++ b/src/app_helpers.py @@ -22,6 +22,8 @@ def abs_join(base_dir: str, rel: str) -> str: def inside_base_dir(base_dir: str, path: str) -> bool: """Check if path is inside base directory.""" + if not isinstance(base_dir, str) or not isinstance(path, str): + return False base = os.path.realpath(base_dir) p = os.path.realpath(path) try: diff --git a/tests/test_inside_base_dir_nonstring.py b/tests/test_inside_base_dir_nonstring.py new file mode 100644 index 0000000..d738b9e --- /dev/null +++ b/tests/test_inside_base_dir_nonstring.py @@ -0,0 +1,19 @@ +"""Regression: inside_base_dir must fail closed on a non-string input. + +The `os.path.realpath(path)` calls run before the try/except (which only wraps +commonpath), so a None / non-string path raised TypeError out of this +path-safety check instead of returning False. +""" +from src.app_helpers import inside_base_dir + + +def test_non_string_fails_closed(): + assert inside_base_dir("/tmp", None) is False + assert inside_base_dir("/tmp", 123) is False + assert inside_base_dir(None, "/tmp/x") is False + + +def test_real_containment_still_works(tmp_path): + base = str(tmp_path) + assert inside_base_dir(base, str(tmp_path / "a.txt")) is True + assert inside_base_dir(base, "/etc/passwd") is False