From 25d5431024c27772db62a4dd4a7aa483e809c2f7 Mon Sep 17 00:00:00 2001 From: D3M-Sudo <264661602+D3M-Sudo@users.noreply.github.com> Date: Mon, 17 Aug 2026 10:26:40 +0000 Subject: [PATCH] security: validate direct sensitive paths in path_validator Ensure validate_path checks both direct input paths and realpath resolved paths against SENSITIVE_PATHS to prevent direct scanning of sensitive system directories. Add unit tests for path validation. --- src/core/path_validator.py | 25 +++++++++++++------- tests/test_path_validator.py | 44 ++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 tests/test_path_validator.py diff --git a/src/core/path_validator.py b/src/core/path_validator.py index 5fdb28f..a9a88e6 100644 --- a/src/core/path_validator.py +++ b/src/core/path_validator.py @@ -44,20 +44,29 @@ def not_path_traversal(path: str) -> bool: return ".." not in Path(path).parts -def not_symlink_to_sensitive(path: str) -> bool: - """Il path non deve essere un symlink che punta a un path sensibile.""" - if not os.path.islink(path): - return True +def not_sensitive_path(path: str) -> bool: + """Il path non deve essere un path sensibile né un symlink a un path sensibile.""" try: resolved = os.path.realpath(path) except OSError: - return False + resolved = path + for sensitive in SENSITIVE_PATHS: - if resolved == sensitive or resolved.startswith(sensitive + os.sep): + if ( + path == sensitive + or path.startswith(sensitive + os.sep) + or resolved == sensitive + or resolved.startswith(sensitive + os.sep) + ): return False return True +def not_symlink_to_sensitive(path: str) -> bool: + """Funzione di compatibilità: verifica che il path non sia sensibile.""" + return not_sensitive_path(path) + + def validate_path(path: str) -> tuple[bool, str | None]: """Valida un path di input per la scansione. @@ -69,6 +78,6 @@ def validate_path(path: str) -> tuple[bool, str | None]: return False, f"Path inesistente o non leggibile: {path}" if not not_path_traversal(path): return False, f"Path traversal non ammesso: {path}" - if not not_symlink_to_sensitive(path): - return False, f"Symlink a path sensibile non ammesso: {path}" + if not not_sensitive_path(path): + return False, f"Path sensibile non ammesso: {path}" return True, None diff --git a/tests/test_path_validator.py b/tests/test_path_validator.py new file mode 100644 index 0000000..018351e --- /dev/null +++ b/tests/test_path_validator.py @@ -0,0 +1,44 @@ +import os +import tempfile +from src.core.path_validator import validate_path + + +def test_validate_path_sensitive_direct(): + valid, reason = validate_path("/etc/shadow") + assert not valid + assert "sensibile" in reason or "non leggibile" in reason + + +def test_validate_path_sensitive_proc(): + valid, reason = validate_path("/proc") + assert not valid + + +def test_validate_path_sensitive_symlink(): + with tempfile.TemporaryDirectory() as tmpdir: + symlink_path = os.path.join(tmpdir, "shadow_link") + try: + os.symlink("/etc/shadow", symlink_path) + valid, reason = validate_path(symlink_path) + assert not valid + assert "sensibile" in reason or "non leggibile" in reason + except OSError: + pass + + +def test_validate_path_normal_file(): + with tempfile.NamedTemporaryFile(delete=False) as tmpfile: + tmp_name = tmpfile.name + try: + valid, reason = validate_path(tmp_name) + assert valid + assert reason is None + finally: + if os.path.exists(tmp_name): + os.unlink(tmp_name) + + +def test_validate_path_traversal(): + valid, reason = validate_path("/tmp/../etc/passwd") + assert not valid + assert "traversal" in reason.lower()