This document details the security audit conducted on the AI Credit Dispute Platform and the fixes implemented.
Overall Risk Level: MEDIUM (with fixes applied)
Deployment Scope: Internal use only on trusted networks
Audit Date: May 30, 2026
Problem: SMTP passwords were exposed via command-line arguments, visible in:
ps auxprocess listings.bash_history,.zsh_historyshell history/proc/[PID]/cmdlineenvironment inspection
Solution Implemented:
- Removed
--smtp-passwordCLI argument entirely - Credentials now read from environment variables only:
SMTP_PASSWORDSMTP_SERVERSMTP_USERSMTP_PORTSMTP_SENDER
Usage:
export SMTP_PASSWORD="your_password"
export SMTP_SERVER="smtp.gmail.com"
export SMTP_USER="your_email@gmail.com"
export SMTP_PORT="587"
export SMTP_SENDER="your_email@gmail.com"
python -m ai_dispute_platform.pipeline.cli --notify recipient@example.com --watch /path/to/pdfsProblem: Uploaded PDFs (containing sensitive customer data) were deleted with regular unlink(), allowing recovery.
Solution Implemented:
- Added
secure_delete()function to web.py (3-pass random overwrite) - All uploaded PDFs are securely deleted after processing
- All temporary files use secure deletion
Implementation:
def secure_delete(file_path: str) -> None:
"""Overwrite a file three times with random data before deleting it."""
# ... overwrites with 3 passes of random data
os.urandom(file_size)Problem: No tracking of:
- Who accessed the system
- What files were processed
- Processing results or failures
- Security events
Solution Implemented:
- Added comprehensive audit logging to web.py
- All operations logged with timestamp, IP address, filename, and result
- Audit log:
audit.login project directory
Logged Events:
- UPLOAD: File upload attempts (success/failure with validation details)
- PROCESS: Processing job results (success/failure, no full traceback exposure)
- STATUS: Status checks (user IP and requested job)
- DOWNLOAD: File downloads (success/failure, file size)
Log Format:
[2026-05-30 14:32:45] Event=UPLOAD | IP=127.0.0.1 | File=credit_report.pdf | Result=SUCCESS | Output=a1b2c3d4e5f6
[2026-05-30 14:33:12] Event=PROCESS | Job=a1b2c3d4e5f6 | Result=SUCCESS
[2026-05-30 14:33:15] Event=DOWNLOAD | IP=127.0.0.1 | File=sample_report.pdf | Result=SUCCESS | Output=45678
Problem: No validation of:
- File size (could upload terabyte files)
- Actual file type (non-PDF files renamed as .pdf)
- PDF integrity
Solution Implemented:
- Added file size limits: 1 KB minimum, 100 MB maximum
- Added magic number verification (checks for
%PDFheader) - Added file validation before processing
- Rejects invalid/malformed PDFs
Validation Checks:
def validate_upload_file(file) -> tuple[bool, str]:
# ✅ Extension check
# ✅ File size check (MIN_FILE_SIZE=1KB, MAX_FILE_SIZE=100MB)
# ✅ PDF magic number verificationProblem: Potential directory traversal via ../ sequences or symlink attacks in filename parameter.
Solution Implemented:
- Added path normalization and validation
- Verified resolved path stays within job directory
- Checked symlink targets (prevented symlink escape)
- Validated filename exists in authorized file list
Protection:
file_path = file_path.resolve() # Normalize
job_dir_resolved = job_dir.resolve()
if not str(file_path).startswith(str(job_dir_resolved)):
return abort(403) # Path traversal detectedProblem: Full Python tracebacks exposed to users, revealing code structure and internal implementation details.
Solution Implemented:
- Removed traceback exposure from user-facing error responses
- Log full exceptions server-side only (in audit.log)
- Return generic error messages to users
Before:
{"error": ["Traceback (most recent call last):", " File ...", "IndexError: list index out of range"]}After:
{"error": "Processing failed. See server logs for details."}Severity: 🔴 CRITICAL
Status:
Current system accepts any string starting with "LIC-" as valid license. Full fix requires:
- Cryptographic signature verification
- License server validation
- Hardware/machine ID binding
- Activation tracking
Recommendation: Implement proper cryptographic license system before commercial deployment.
Severity: 🔴 CRITICAL
Status:
Trial status stored in trial_status.json can be reset by:
- Deleting the file
- Setting system clock back
- Modifying JSON content
Recommendation: Implement server-side trial tracking before commercial deployment.
Severity: 🔴 CRITICAL
Status:
Web interface has NO authentication, API keys, or access control. Anyone on the network can:
- Upload PDFs
- Download reports
- See processing status
Current Mitigation:
- Audit logging captures all access by IP address
- Intended for "trusted networks only"
Recommended Fixes:
- Add API key authentication
- Implement IP whitelisting
- Add Flask-HTTPAuth or similar
- Use HTTPS/TLS
Severity: 🟠 HIGH
Status:
Endpoints are vulnerable to:
- Upload bombing (disk exhaustion)
- Processing queue flooding (CPU exhaustion)
- Status checking loop (DoS)
Recommended Fix:
from flask_limiter import Limiter
limiter = Limiter(app)
@limiter.limit("5 per minute")
def upload():
...Severity: 🟠 HIGH
Status:
Web interface runs over HTTP only. PDFs and reports transmitted in plaintext.
Recommendation:
- Use nginx/Apache as reverse proxy with TLS
- Enable
--ssl-certand--ssl-keyoptions - Enforce HTTPS redirect
-
Network Isolation
# Only allow access from trusted IP ranges firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="8080" accept'
-
SMTP Credential Management
# Use .env file (never commit to git) cat > .env << EOF SMTP_PASSWORD="your_secure_password" SMTP_SERVER="smtp.gmail.com" SMTP_USER="your_email@gmail.com" SMTP_PORT="587" SMTP_SENDER="your_email@gmail.com" EOF # Load before running source .env python -m ai_dispute_platform.pipeline.cli ...
-
Audit Log Rotation
# Prevent unbounded growth logrotate -f /etc/logrotate.d/ai-dispute.conf -
Permission Restrictions
chmod 600 audit.log # Only owner can read chmod 700 /tmp/ai_dispute_platform_web # Only owner can access
-
Temporary File Cleanup
- Old job directories auto-cleaned after 24 hours
- Configure via cleanup_old_jobs() function
-
Never commit credentials
# .gitignore .env *.key audit.log
-
Use test email addresses
export SMTP_USER="test@example.com"
-
Enable debug logging
import logging logging.basicConfig(level=logging.DEBUG)
- ✅ Audit logging added - All operations now tracked
- ✅ Secure file deletion added - PDFs overwritten before deletion
- ✅ File validation added - PDFs verified before processing
- ✅ Path traversal protection added - Download endpoint hardened
⚠️ Single-threaded processing - Serialized job queue (prevents DoS scaling)⚠️ Intended for local/trusted networks - Not suitable for public internet
- ❌ Rate limiting (Flask-Limiter)
- ❌ Web authentication (API keys, OAuth)
- ❌ HTTPS/TLS support (requires reverse proxy)
- ❌ Proper license verification (cryptographic)
- ❌ Server-side trial tracking
- ❌ IP whitelisting
- ❌ User management
- ❌ Role-based access control (RBAC)
# Upload a PDF
# Check /tmp/ai_dispute_platform_web/[job_id]/upload.pdf
# After processing, verify file is gone (and not recoverable)
strings /tmp/ai_dispute_platform_web/[job_id]/ | grep PDF
# Should return nothing (or only remnants of overwritten data)tail -f audit.log
# Try uploading files from different IPs
# Observe all access logged with IP, filename, result# Try uploading a text file as .pdf
curl -F "file=@test.txt" http://localhost:8080/upload
# Should reject with "not a valid PDF"
# Try uploading >100MB file
# Should reject with size limit error# Try to get SMTP password from process
ps aux | grep python
# Should NOT see SMTP_PASSWORD in command line
# Verify environment variables used instead
echo $SMTP_PASSWORD- ✅ OWASP Top 10: Path Traversal (A03:2021)
- ✅ OWASP Top 10: Broken Access Control (A01:2021)
- ✅ OWASP Top 10: Injection (A03:2021)
- ✅ CWE-22: Improper Limitation of a Pathname to a Restricted Directory
- ✅ CWE-434: Unrestricted Upload of File with Dangerous Type
- ✅ CWE-312: Cleartext Storage of Sensitive Information
- ❌ NIST SP 800-53: Authentication (AC-2)
- ❌ NIST SP 800-53: Encryption (SC-7)
- ❌ HIPAA: Business Associate Agreement requirements
- ❌ PCI DSS: Payment card data handling
- ❌ SOC 2: Audit logging standards
- ❌ ISO 27001: Information security management
For security concerns:
- Check the fixes documented above
- Review the implementation in source code
- Run the test procedures in this file
- Contact: contact@clearwatercodes.com
Last Updated: 2026-05-30
Next Review: Recommended after 6 months or before major deployment