diff --git a/litellm/llms/litellm_proxy/skills/prompt_injection.py b/litellm/llms/litellm_proxy/skills/prompt_injection.py index 2b86f74122b..86b6e223512 100644 --- a/litellm/llms/litellm_proxy/skills/prompt_injection.py +++ b/litellm/llms/litellm_proxy/skills/prompt_injection.py @@ -5,6 +5,7 @@ Handles extraction of skill content (SKILL.md) from stored ZIP files and injection into the system prompt for non-Anthropic models. """ +import posixpath import zipfile from io import BytesIO from typing import Any, Dict, List, Optional @@ -103,8 +104,18 @@ class SkillPromptInjectionHandler: else: clean_path = name - if clean_path: - files[clean_path] = zf.read(name) + if not clean_path: + continue + + # Ensure the path stays within the intended directory + normalized = posixpath.normpath(clean_path) + if normalized.startswith("..") or posixpath.isabs(normalized): + verbose_logger.warning( + f"SkillPromptInjectionHandler: Skipping entry with invalid path in skill {skill.skill_id}: {name}" + ) + continue + + files[normalized] = zf.read(name) except Exception as e: verbose_logger.warning( f"SkillPromptInjectionHandler: Error extracting files from skill {skill.skill_id}: {e}" diff --git a/litellm/llms/litellm_proxy/skills/sandbox_executor.py b/litellm/llms/litellm_proxy/skills/sandbox_executor.py index a5c0a539c96..af13d3c091d 100644 --- a/litellm/llms/litellm_proxy/skills/sandbox_executor.py +++ b/litellm/llms/litellm_proxy/skills/sandbox_executor.py @@ -94,9 +94,15 @@ class SkillsSandboxExecutor: # Create a temp directory to stage files with tempfile.TemporaryDirectory() as tmpdir: + tmpdir_abs = os.path.abspath(tmpdir) for path, content in skill_files.items(): # Create the file in temp directory - local_path = os.path.join(tmpdir, path) + local_path = os.path.abspath(os.path.join(tmpdir, path)) + if not local_path.startswith(tmpdir_abs + os.sep): + verbose_logger.warning( + f"SkillsSandboxExecutor: Skipping file with invalid path: {path}" + ) + continue os.makedirs(os.path.dirname(local_path), exist_ok=True) with open(local_path, "wb") as f: f.write(content) diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index a62f34764d3..88a2e1e95cd 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -2978,7 +2978,7 @@ class PrismaClient: detail={"error": f"No token passed in. Token={token}"}, ) - sql_query = f""" + sql_query = """ SELECT v.*, t.spend AS team_spend,