Skip to content

Commit 131d75b

Browse files
Copilotamitdevx
andcommitted
Address code review feedback: improve path traversal protection and add SECRET_KEY warning
Co-authored-by: amitdevx <110670491+amitdevx@users.noreply.github.com>
1 parent 2c8fc49 commit 131d75b

2 files changed

Lines changed: 42 additions & 9 deletions

File tree

FileFlow/backend/config.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
import os
2+
import warnings
23

34
class Config:
4-
SECRET_KEY = os.environ.get('SECRET_KEY') or os.urandom(24)
5+
# SECRET_KEY should be set via environment variable in production
6+
# A random fallback is used only for development; this will invalidate
7+
# sessions on every restart
8+
SECRET_KEY = os.environ.get('SECRET_KEY')
9+
if not SECRET_KEY:
10+
warnings.warn(
11+
"SECRET_KEY not set in environment. Using random key. "
12+
"Sessions will be invalidated on restart. "
13+
"Set SECRET_KEY environment variable for production use.",
14+
RuntimeWarning
15+
)
16+
SECRET_KEY = os.urandom(24)
17+
518
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///fileflow.db'
619
SQLALCHEMY_TRACK_MODIFICATIONS = False
720
UPLOAD_FOLDER = 'user_files'

FileFlow/backend/services/compression_service.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,39 @@
66
class CompressionService:
77
@staticmethod
88
def _is_safe_path(base_path, target_path):
9-
"""Check if target path is within base path (prevents directory traversal)"""
9+
"""Check if target path is within base path (prevents directory traversal)
10+
11+
Note: This validates the path string without resolving symlinks to prevent
12+
symlink-based attacks. The check uses string comparison after normalization.
13+
"""
1014
try:
1115
base = Path(base_path).resolve()
12-
target = Path(target_path).resolve()
13-
return target.is_relative_to(base)
16+
# Normalize target without fully resolving to prevent symlink attacks
17+
# Join base with target and check if it stays within base
18+
full_path = (base / target_path).resolve()
19+
return full_path.is_relative_to(base)
1420
except (ValueError, RuntimeError):
1521
return False
1622

1723
@staticmethod
1824
def _safe_extract_member(archive_path, member_name, extract_to):
19-
"""Validate that extracted file stays within extract_to directory"""
20-
target_path = Path(extract_to) / member_name
21-
if not CompressionService._is_safe_path(extract_to, target_path):
25+
"""Validate that extracted file stays within extract_to directory
26+
27+
Rejects paths with:
28+
- Absolute paths
29+
- Parent directory references (..)
30+
- Paths that escape the extraction directory
31+
"""
32+
# Reject absolute paths
33+
if Path(member_name).is_absolute():
34+
raise ValueError(f"Absolute path in archive is not allowed: {member_name}")
35+
36+
# Reject paths with parent directory references
37+
if '..' in Path(member_name).parts:
38+
raise ValueError(f"Path traversal attempt detected: {member_name}")
39+
40+
# Validate the final path stays within extraction directory
41+
if not CompressionService._is_safe_path(extract_to, member_name):
2242
raise ValueError(f"Attempted path traversal in archive: {member_name}")
2343
return True
2444

@@ -61,11 +81,11 @@ def extract_tar(archive_path, extract_to):
6181
# Validate all members before extraction to prevent path traversal
6282
for member in tarf.getmembers():
6383
CompressionService._safe_extract_member(archive_path, member.name, extract_to)
64-
# Use data filter for Python 3.12+ or validate manually for earlier versions
84+
# Use data filter for Python 3.11.4+ or validate manually for earlier versions
6585
try:
6686
tarf.extractall(extract_to, filter='data')
6787
except TypeError:
68-
# Python < 3.12 doesn't support filter parameter, but we already validated
88+
# Python < 3.11.4 doesn't support filter parameter, but we already validated
6989
tarf.extractall(extract_to)
7090

7191
@staticmethod

0 commit comments

Comments
 (0)