diff --git a/utils/download/repo_downloader.py b/utils/download/repo_downloader.py index b7053a0c..30af6c5d 100644 --- a/utils/download/repo_downloader.py +++ b/utils/download/repo_downloader.py @@ -149,11 +149,19 @@ def get_changed_files(self, old_sha: str, new_sha: str) -> Optional[List[Dict]]: def _resolve_local_path(self, repo_path: str) -> Optional[Path]: """Map a repo-relative path (skins/... or resources/...) to a local path.""" from utils.core.paths import get_user_data_dir + from utils.core.safe_extract import is_safe_path if repo_path.startswith('skins/'): - return self.target_dir / repo_path[len('skins/'):] + base = self.target_dir + candidate = base / repo_path[len('skins/'):] elif repo_path.startswith('resources/'): - return get_user_data_dir() / "resources" / repo_path[len('resources/'):] - return None + base = get_user_data_dir() / "resources" + candidate = base / repo_path[len('resources/'):] + else: + return None + if not is_safe_path(base, candidate): + log.error(f"[SECURITY] Blocked unsafe repo path: {repo_path}") + return None + return candidate def download_changed_files(self, changed_files: List[Dict]) -> bool: """Download changed files individually via raw.githubusercontent.com. diff --git a/utils/download/skin_downloader.py b/utils/download/skin_downloader.py index 591b9e5e..89e5f3f1 100644 --- a/utils/download/skin_downloader.py +++ b/utils/download/skin_downloader.py @@ -11,6 +11,7 @@ from typing import Callable, List, Dict, Optional from utils.core.logging import get_logger from utils.core.paths import get_skins_dir +from utils.core.safe_extract import is_safe_path from config import ( API_POLITENESS_DELAY_S, APP_USER_AGENT, DEFAULT_SKIN_DOWNLOAD_TIMEOUT_S, SKIN_DOWNLOAD_STREAM_TIMEOUT_S @@ -110,7 +111,11 @@ def download_champion_skins(self, champion: str, force_update: bool = False) -> for skin_file in skin_files: filename = skin_file['name'] local_path = champion_dir / filename - + + if not is_safe_path(champion_dir, local_path): + log.error(f"[SECURITY] Blocked unsafe filename from API: {filename}") + continue + # Skip if file exists and we're not forcing update if local_path.exists() and not force_update: log.debug(f"Skipping existing file: {filename}")