Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions src/core/path_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
44 changes: 44 additions & 0 deletions tests/test_path_validator.py
Original file line number Diff line number Diff line change
@@ -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()