Problem: The system allowed access to files outside authorized directories via sequences like ../../../etc/passwd.
Implemented solutions:
- β
Module
app/utils/security.pywith strict path validation - β
Class
PathSecurityValidatorto sanitize and validate all paths - β Verification that files remain within authorized directories
- β
Blocking of dangerous patterns (
../,~/,/etc/, etc.)
Problem: File upload without validation allowing malicious file writing.
Implemented solutions:
- β Validation of allowed file extensions
- β Filename sanitization (removal of dangerous characters)
- β File size limitation (1000MB by default)
- β Validation of destination directories
Problem: Recursive reading of all files without restriction.
Implemented solutions:
- β Whitelist of authorized directories
- β Exclusion of system and hidden files
# Usage
validated_path = PathSecurityValidator.validate_file_path(user_input)
safe_filename = PathSecurityValidator.validate_filename(filename)Features:
- Detection of dangerous patterns
- Path normalization
- Extension validation
- Base directory control
# Access verification
can_access = FileAccessController.can_read_file(file_path, allowed_dirs)
content = FileAccessController.get_restricted_file_content(file_path, max_size)Features:
- Verification of authorized directories
- File size limitation
- Permission management
Integration in main.py:
Configuration for Users: The rate limiting and time window for security are set using environment variables. You can adjust these values in your deployment settings to control how many requests are allowed and over what period.
# Maximum requests allowed per time window
SECURITY_RATE_LIMIT=100
# Time window in seconds
SECURITY_TIME_WINDOW=60These variables should be set in your environment or .env file before starting the backend. The application will automatically use these values to configure the security middleware.
Features:
- β Rate limiting (configurable req/min per IP)
- β
Path traversal detection (
../,/etc/, etc.) - β Suspicious pattern detection (encoded attacks)
- β Large request size blocking (>50MB)
- β Temporary IP blocking (1 hour after violations)
- β File access monitoring and logging
- β Automatic security event logging
What it blocks:
- Path traversal:
../../../etc/passwd - Rate limits: >100 requests/minute from same IP
- Suspicious headers: Headers containing attack patterns
- System paths:
/etc/,/proc/,C:\Windows\
uploads/- Files uploaded by usersapp/uploads/- Alternative upload directoryapp/ptx/- PTX dataapp/inputs/- Input files
/etc/,/proc/,/sys/(Unix)C:\Windows\,C:\Users\(Windows)- Any system or user directory
.csv,.tsv- Tabular data files.json- JSON data.xlsx,.xls- Excel files.parquet- Parquet format.avro- Avro format.feather,.orc- Other data formats
.txt- Text files.md- Markdown.yml,.yaml- YAML configuration.xml- XML data.log- Log files
Dataset credentials (MySQL passwords, API tokens, PTX tokens, etc.) are encrypted at rest in MongoDB using Fernet (AES-128-CBC + HMAC-SHA256).
| Priority | Source | How to set |
|---|---|---|
| 1 | FIELD_ENCRYPTION_KEY env var |
Explicit dedicated Fernet key |
| 2 | JWT_SECRET_KEY env var |
Automatic β key derived via HKDF-SHA256, no extra config needed |
| 3 | Neither | Plain text stored + warning in logs |
If JWT_SECRET_KEY is already set (required for JWT auth), dataset credentials are automatically encrypted β no additional variable needed.
If you want to use a separate encryption key (recommended in production for key rotation):
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"Then add it to your .env or docker-compose.yml:
FIELD_ENCRYPTION_KEY=your-generated-key-here| Dataset type | Encrypted fields |
|---|---|
| MySQL | password |
| MongoDB | uri (contains credentials) |
| Elasticsearch | password, key, bearerToken |
| PTX/PDC | token, refreshToken, secret_key, service_key |
| API | bearerToken, basicToken, clientSecret |
Existing plain-text values in the database are readable without any action. New writes and updates are automatically encrypted. The enc: prefix distinguishes encrypted values from plain ones.
# Upload directory (optional, default: uploads)
UPLOAD_DIR=uploads
# Max file size (optional, default: 100MB)
MAX_FILE_SIZE=100MB
# WhiteList directory who can bypass path restriction security
# Example by default /opt is not readeable to avoid unauthorized access to 3rd app conf
# You can add a sub directory on this list to avoid this exclusion to give access to subpath
DIRECTORY_WHITE_LIST=/opt/uploads,/opt/staticSecurity events are logged in security.log:
[SECURITY] 2024-01-01 12:00:00 - WARNING - PATH_TRAVERSAL_BLOCKED: ../../../etc/passwd from IP 192.168.1.100
[SECURITY] 2024-01-01 12:01:00 - ERROR - SUSPICIOUS_PATTERN_DETECTED: Multiple path traversal attempts from IP 192.168.1.100
[SECURITY] 2024-01-01 12:02:00 - CRITICAL - IP_BLOCKED: IP 192.168.1.100 blocked for 1 hour
PATH_TRAVERSAL_BLOCKED- Path traversal attemptSUSPICIOUS_PATTERN_DETECTED- Suspicious pattern detectedRATE_LIMIT_EXCEEDED- Rate limit exceededFILE_ACCESS- File accessUPLOAD_BLOCKED- Upload blocked
cd backendApi
python -m pytest tests/security/test_path_security.py -v- β Unix/Windows path traversal
- β Null byte injection
- β Windows reserved filenames
- β Unauthorized extensions
- β Excessive file sizes
- β Access outside authorized directories
- Environment variables: Configure all tokens/secrets
- HTTPS: Use HTTPS exclusively
- Reverse Proxy: Nginx/Apache with additional limitations
- Monitoring: Monitor security logs
- Backup: Regularly backup authorized data only
# Limit upload size
client_max_body_size 100M;
# Security headers
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
# Block access to sensitive files
location ~ /\. {
deny all;
}
location ~ \.(env|ini|conf)$ {
deny all;
}