Skip to content

Commit 80c6bd0

Browse files
CopilotMte90
andcommitted
Improve path validation for cross-platform security
Co-authored-by: Mte90 <403283+Mte90@users.noreply.github.com>
1 parent ddaa33a commit 80c6bd0

1 file changed

Lines changed: 13 additions & 8 deletions

File tree

ai/analyzer.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,8 @@ def _get_chunk_text(database_path: str, file_id: int, chunk_index: int) -> Optio
260260
Uses project_path metadata and file path to read the actual file.
261261
262262
Security: Validates that the resolved file path is within the project directory
263-
to prevent path traversal attacks.
263+
to prevent path traversal attacks using os.path.commonpath for cross-platform safety.
264264
"""
265-
from db.operations import get_project_metadata
266-
267265
conn = _connect_db(database_path)
268266
try:
269267
cur = conn.cursor()
@@ -285,13 +283,20 @@ def _get_chunk_text(database_path: str, file_id: int, chunk_index: int) -> Optio
285283
logger.error("Project path not found in metadata, cannot read file from filesystem")
286284
raise RuntimeError("Project path metadata is missing - indexing may not have completed properly")
287285

288-
# Construct full file path and normalize to prevent path traversal
289-
full_path = os.path.normpath(os.path.join(project_path, file_path))
290-
normalized_project_path = os.path.normpath(project_path)
286+
# Construct full file path and resolve to absolute path
287+
full_path = os.path.abspath(os.path.join(project_path, file_path))
288+
normalized_project_path = os.path.abspath(project_path)
291289

292290
# Security check: ensure the resolved path is within the project directory
293-
if not full_path.startswith(normalized_project_path + os.sep) and full_path != normalized_project_path:
294-
logger.error(f"Path traversal attempt detected: {file_path} resolves outside project directory")
291+
# Using os.path.commonpath for cross-platform safety (handles Windows/Unix path separators)
292+
try:
293+
common = os.path.commonpath([full_path, normalized_project_path])
294+
if common != normalized_project_path:
295+
logger.error(f"Path traversal attempt detected: {file_path} resolves outside project directory")
296+
return None
297+
except ValueError:
298+
# Different drives on Windows
299+
logger.error(f"Path traversal attempt detected: {file_path} is on a different drive")
295300
return None
296301

297302
# Read file content from filesystem

0 commit comments

Comments
 (0)