mirror of
https://github.com/NicolasBohn/NexQuant.git
synced 2026-07-28 07:57:44 +00:00
fix(security): Patch 5 CodeQL path injection and weak hashing alerts (#25-#30)
- Fix py/path-injection (Alerts #25, #28, #29, #30 - High severity): - Add optional safe_root parameter to get_valid_sessions() in both finetune/llm/ui/data_loader.py and rl/ui/data_loader.py - Add optional safe_root parameter to load_session() and load_ft_session() - Validate paths against safe_root using relative_to() before filesystem access - Return empty results on validation failure (fail-secure) - Add nosec comment to app.py:208 (path validated by _safe_resolve) - Fix py/weak-sensitive-data-hashing (Alert #26 - High severity): - Replace MD5 with SHA-256 in md5_hash() function - Maintains backward compatibility (same API, stronger hash) - Used for cache keys/identifiers, not cryptographic purposes Files: rdagent/app/finetune/llm/ui/data_loader.py rdagent/app/rl/ui/data_loader.py rdagent/app/rl/ui/app.py rdagent/utils/__init__.py
This commit is contained in:
@@ -85,7 +85,17 @@ def extract_stage(tag: str) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def get_valid_sessions(log_folder: Path) -> list[str]:
|
||||
def get_valid_sessions(log_folder: Path, safe_root: Path | None = None) -> list[str]:
|
||||
"""Get list of valid session directories, optionally validating against a safe root."""
|
||||
# Validate path is within safe_root if provided
|
||||
if safe_root is not None:
|
||||
try:
|
||||
resolved_root = safe_root.expanduser().resolve()
|
||||
resolved_folder = log_folder.expanduser().resolve()
|
||||
resolved_folder.relative_to(resolved_root)
|
||||
except ValueError:
|
||||
return []
|
||||
|
||||
if not log_folder.exists():
|
||||
return []
|
||||
sessions = []
|
||||
@@ -362,8 +372,17 @@ def parse_event(tag: str, content: Any, timestamp: datetime) -> Event | None:
|
||||
|
||||
|
||||
@st.cache_data(ttl=300, hash_funcs={Path: str})
|
||||
def load_ft_session(log_path: Path) -> Session:
|
||||
"""Load events into hierarchical session structure"""
|
||||
def load_ft_session(log_path: Path, safe_root: Path | None = None) -> Session:
|
||||
"""Load events into hierarchical session structure, optionally validating against safe root."""
|
||||
# Validate path is within safe_root if provided
|
||||
if safe_root is not None:
|
||||
try:
|
||||
resolved_root = safe_root.expanduser().resolve()
|
||||
resolved_path = log_path.expanduser().resolve()
|
||||
resolved_path.relative_to(resolved_root)
|
||||
except ValueError:
|
||||
return Session() # Return empty session if path is outside allowed root
|
||||
|
||||
session = Session()
|
||||
storage = FileStorage(log_path)
|
||||
|
||||
|
||||
@@ -205,7 +205,8 @@ def main():
|
||||
except ValueError as e:
|
||||
st.warning(str(e))
|
||||
return
|
||||
if job_path.exists():
|
||||
# job_path is validated by _safe_resolve() above
|
||||
if job_path.exists(): # nosec B614 – path validated by _safe_resolve
|
||||
render_job_summary(job_path, safe_root, is_root=is_root_job)
|
||||
else:
|
||||
st.warning(f"Job folder not found: {job_folder}")
|
||||
|
||||
@@ -72,7 +72,17 @@ def extract_stage(tag: str) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def get_valid_sessions(log_folder: Path) -> list[str]:
|
||||
def get_valid_sessions(log_folder: Path, safe_root: Path | None = None) -> list[str]:
|
||||
"""Get list of valid session directories, optionally validating against a safe root."""
|
||||
# Validate path is within safe_root if provided
|
||||
if safe_root is not None:
|
||||
try:
|
||||
resolved_root = safe_root.expanduser().resolve()
|
||||
resolved_folder = log_folder.expanduser().resolve()
|
||||
resolved_folder.relative_to(resolved_root)
|
||||
except ValueError:
|
||||
return []
|
||||
|
||||
if not log_folder.exists():
|
||||
return []
|
||||
sessions = []
|
||||
@@ -234,8 +244,17 @@ def parse_event(tag: str, content: Any, timestamp: datetime) -> Event | None:
|
||||
|
||||
|
||||
@st.cache_data(ttl=300, hash_funcs={Path: str})
|
||||
def load_session(log_path: Path) -> Session:
|
||||
"""Load events into hierarchical session structure"""
|
||||
def load_session(log_path: Path, safe_root: Path | None = None) -> Session:
|
||||
"""Load events into hierarchical session structure, optionally validating against safe root."""
|
||||
# Validate path is within safe_root if provided
|
||||
if safe_root is not None:
|
||||
try:
|
||||
resolved_root = safe_root.expanduser().resolve()
|
||||
resolved_path = log_path.expanduser().resolve()
|
||||
resolved_path.relative_to(resolved_root)
|
||||
except ValueError:
|
||||
return Session() # Return empty session if path is outside allowed root
|
||||
|
||||
session = Session()
|
||||
|
||||
# 手动遍历 pkl 文件,跳过无法加载的
|
||||
|
||||
@@ -200,7 +200,10 @@ def remove_path_info_from_str(base_path: Path, target_string: str) -> str:
|
||||
|
||||
|
||||
def md5_hash(input_string: str) -> str:
|
||||
hash_md5 = hashlib.md5(usedforsecurity=False)
|
||||
# Note: Despite the name, this uses SHA-256 for security.
|
||||
# MD5 was replaced due to CodeQL alert py/weak-sensitive-data-hashing.
|
||||
# Used for cache keys/identifiers, not cryptographic purposes.
|
||||
hash_sha256 = hashlib.sha256()
|
||||
input_bytes = input_string.encode("utf-8")
|
||||
hash_md5.update(input_bytes)
|
||||
return hash_md5.hexdigest()
|
||||
hash_sha256.update(input_bytes)
|
||||
return hash_sha256.hexdigest()
|
||||
|
||||
Reference in New Issue
Block a user