- Added Security Handoff Report detailing resolved issues and current configurations. - Implemented CSRF protection using Flask-WTF, including token management in templates and JavaScript. - Created standardized error handling module to log detailed errors while returning generic messages. - Developed phone number validation module to ensure compliance with E.164 standards. - Added CSV injection prevention measures during file uploads. - Updated installation guide for clarity and completeness. - Created script to update API keys from Android device, ensuring secure key management. - Enhanced Docker security configurations to remove privileged mode and host networking. - Implemented logging and sanitization for error messages to prevent information disclosure. - Added verification script to test security setup flow and validate configurations.
215 lines
6.4 KiB
Markdown
215 lines
6.4 KiB
Markdown
# Security Handoff Report
|
|
|
|
**Date:** 2026-01-01
|
|
**Project:** SMS Campaign Manager
|
|
**Status:** All critical, high, and medium priority issues resolved
|
|
|
|
---
|
|
|
|
## Completed Security Fixes
|
|
|
|
| Issue | Severity | Status |
|
|
|-------|----------|--------|
|
|
| Docker privileged mode | Critical | Fixed |
|
|
| Docker host networking | Critical | Fixed |
|
|
| Hardcoded API secret | Critical | Fixed |
|
|
| Command injection (IP detection) | Critical | Fixed |
|
|
| API keys in query parameters | High | Fixed |
|
|
| No security headers | High | Fixed |
|
|
| SameSite cookie too permissive | Medium | Fixed |
|
|
| Login redirect error | Medium | Fixed |
|
|
| No CSRF protection | Medium | Fixed |
|
|
| Error messages expose internal details | Medium | Fixed |
|
|
| No input validation on phone numbers | Medium | Fixed |
|
|
| CSV injection not prevented | Medium | Fixed |
|
|
|
|
---
|
|
|
|
## Security Headers Now Active
|
|
|
|
All responses now include:
|
|
```
|
|
X-Content-Type-Options: nosniff
|
|
X-Frame-Options: DENY
|
|
X-XSS-Protection: 1; mode=block
|
|
Referrer-Policy: strict-origin-when-cross-origin
|
|
Permissions-Policy: geolocation=(), microphone=(), camera=()
|
|
```
|
|
|
|
---
|
|
|
|
## CSRF Protection
|
|
|
|
Flask-WTF CSRF protection is now enabled:
|
|
- All state-changing requests require CSRF token
|
|
- Token available via meta tag in templates: `<meta name="csrf-token">`
|
|
- JavaScript helper `secureFetch()` in common.js automatically includes token
|
|
- Login endpoint exempt (no session before login)
|
|
- API key authenticated endpoints exempt (separate auth mechanism)
|
|
|
|
**Files modified:**
|
|
- `src/app.py` - Added CSRFProtect initialization
|
|
- `src/requirements.txt` - Added Flask-WTF==1.2.1
|
|
- `src/templates/base.html` - Added CSRF meta tag
|
|
- `src/static/js/common.js` - Added `getCSRFToken()` and `secureFetch()` helpers
|
|
|
|
---
|
|
|
|
## Error Message Sanitization
|
|
|
|
Created standardized error handler module:
|
|
- `src/core/error_handler.py` - Centralized error handling
|
|
- Logs full error details server-side
|
|
- Returns generic safe messages to clients
|
|
- Prevents internal path/stack trace disclosure
|
|
|
|
**Files updated:**
|
|
- `src/routes/lists.py` - 6 locations
|
|
- `src/routes/conversations.py` - 8 locations
|
|
- `src/routes/api/upload_routes.py` - 4 locations
|
|
|
|
---
|
|
|
|
## Phone Number Validation
|
|
|
|
Created phone validation module:
|
|
- `src/core/phone_validation.py` - Validation and normalization
|
|
- Validates minimum/maximum length (7-15 digits per E.164)
|
|
- Normalizes to consistent format
|
|
- Filters invalid numbers during CSV upload
|
|
|
|
**Features:**
|
|
- `validate_phone_number()` - Returns (is_valid, normalized, error)
|
|
- `normalize_phone_number()` - Strips formatting, keeps digits
|
|
- `format_phone_display()` - Formats for UI display
|
|
|
|
---
|
|
|
|
## CSV Injection Prevention
|
|
|
|
Added sanitization for uploaded CSV files:
|
|
- Prefixes dangerous characters with single quote
|
|
- Prevents formula execution: `=`, `+`, `-`, `@`, `\t`, `\r`, `\n`
|
|
- Applied to all CSV upload endpoints
|
|
|
|
**Functions added to upload_routes.py:**
|
|
- `sanitize_csv_value()` - Sanitizes individual values
|
|
- `sanitize_csv_row()` - Sanitizes entire row dict
|
|
|
|
---
|
|
|
|
## Low Priority / Best Practices (Pending)
|
|
|
|
| Issue | Recommendation |
|
|
|-------|----------------|
|
|
| Database timeout (30s) | Reduce to 5-10 seconds |
|
|
| Rate limiting | Add per-user limiting for authenticated endpoints |
|
|
| Dependency scanning | Add `safety check` to CI/CD |
|
|
| Audit logging | Log failed logins, API usage, admin actions |
|
|
|
|
---
|
|
|
|
## Risk Summary
|
|
|
|
| Severity | Count | Status |
|
|
|----------|-------|--------|
|
|
| Critical | 4 | All Fixed |
|
|
| High | 2 | All Fixed |
|
|
| Medium | 8 | All Fixed |
|
|
| Low | 4 | Pending |
|
|
|
|
**Overall Risk Level:** Very Low (all critical/high/medium resolved)
|
|
|
|
---
|
|
|
|
## Files Modified During Security Review
|
|
|
|
### Phase 1 - Critical/High Fixes:
|
|
| File | Change |
|
|
|------|--------|
|
|
| `docker-compose.yml` | Removed privileged mode and host networking |
|
|
| `android/termux-sms-api-server.py` | Removed default secret, added validation, fixed command injection |
|
|
| `src/routes/auth_routes.py` | Fixed dashboard redirect to campaigns |
|
|
| `src/core/auth.py` | Removed API key query parameter support |
|
|
| `src/app.py` | Added security headers, changed SameSite to Strict |
|
|
|
|
### Phase 2 - Medium Priority Fixes:
|
|
| File | Change |
|
|
|------|--------|
|
|
| `src/app.py` | Added CSRF protection with Flask-WTF |
|
|
| `src/requirements.txt` | Added Flask-WTF dependency |
|
|
| `src/templates/base.html` | Added CSRF meta tag |
|
|
| `src/static/js/common.js` | Added CSRF token helpers |
|
|
| `src/routes/lists.py` | Sanitized error messages |
|
|
| `src/routes/conversations.py` | Sanitized error messages |
|
|
| `src/routes/api/upload_routes.py` | Error sanitization, CSV injection prevention, phone validation |
|
|
|
|
### New Files Created:
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `android/setup-api-key.sh` | Android API key setup script |
|
|
| `scripts/update-api-keys.sh` | Ubuntu API key update script |
|
|
| `src/core/error_handler.py` | Standardized error handling module |
|
|
| `src/core/phone_validation.py` | Phone number validation utilities |
|
|
| `SECURITY_FIXES.md` | Documentation of critical fixes |
|
|
| `test-setup-flow.sh` | Automated validation script |
|
|
|
|
---
|
|
|
|
## Current Security Configuration
|
|
|
|
**API Authentication:**
|
|
- Android (Termux): `SMS_API_SECRET` in `~/.bashrc`
|
|
- Ubuntu (.env): `TERMUX_API_KEY`, `SMS_API_SECRET`
|
|
- Headers only (query parameters disabled)
|
|
|
|
**Docker Security:**
|
|
- Privileged: `false`
|
|
- NetworkMode: `bridge` (isolated)
|
|
|
|
**Session Security:**
|
|
- Cookie: HttpOnly, Secure (when HTTPS), SameSite=Strict
|
|
- Remember Cookie: SameSite=Strict
|
|
- CSRF: Enabled via Flask-WTF
|
|
- Timeout: 24 hours
|
|
|
|
**Response Headers:**
|
|
- X-Frame-Options: DENY
|
|
- X-Content-Type-Options: nosniff
|
|
- X-XSS-Protection: 1; mode=block
|
|
- Referrer-Policy: strict-origin-when-cross-origin
|
|
- Permissions-Policy: restricted
|
|
|
|
**Input Validation:**
|
|
- Phone numbers: Validated and normalized on upload
|
|
- CSV files: Sanitized to prevent formula injection
|
|
- Error messages: Generic responses, full details logged server-side
|
|
|
|
---
|
|
|
|
## Verification Commands
|
|
|
|
```bash
|
|
# Verify Docker security
|
|
docker inspect sms-campaign-manager | grep -E "Privileged|NetworkMode"
|
|
|
|
# Verify security headers
|
|
curl -I http://localhost:5000/health | grep -E "X-Frame|X-Content|X-XSS"
|
|
|
|
# Verify CSRF token endpoint
|
|
curl http://localhost:5000/api/csrf-token
|
|
|
|
# Verify API authentication
|
|
curl -H "X-API-Key: $(grep TERMUX_API_KEY .env | cut -d= -f2)" \
|
|
http://100.107.173.66:5001/health
|
|
|
|
# Run dependency security check
|
|
pip install safety && safety check
|
|
```
|
|
|
|
---
|
|
|
|
**Report generated:** 2026-01-01
|
|
**Last updated:** 2026-01-01 (medium priority fixes implemented)
|
|
**Status:** Ready for production
|