This document outlines security measures implemented in ThreatPilot and best practices for deployment.
What was done:
- Generated new
SECRET_KEYusing cryptographically secure randomness - Generated new
DEFAULT_ADMIN_PASSWORD(strong, 43-character, URL-safe) - Cleared
NVD_API_KEY(regenerate from https://nvd.nist.gov/developers/request-an-api-key) - All credentials in
.envhave been rotated
Action Items:
- IMMEDIATELY: Treat the old NVD API key as compromised. Request a new one from https://nvd.nist.gov/developers/request-an-api-key
- Update database credentials if using the example password
- Generate new secrets for each deployment environment:
python -c "import secrets; print('SECRET_KEY=' + secrets.token_hex(32))" python -c "import secrets; print('DEFAULT_ADMIN_PASSWORD=' + secrets.token_urlsafe(32))"
What was done:
app.pynow validatesDEFAULT_ADMIN_PASSWORDon startup- Rejects passwords shorter than 12 characters
- Rejects known weak defaults: "", "changeme", "admin123", "password", etc.
- Application will refuse to start with weak passwords
Before Deploying:
- Set a unique, strong password (min 12 chars)
- Never use default or test passwords in production
- Store securely in
.env(which is in.gitignore)
What was done:
- Added
_is_valid_webhook_url()function to validate webhook URLs - Blocks all non-HTTPS URLs (http://, file://, gopher://, etc.)
- Blocks private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- Blocks loopback addresses (127.0.0.1, ::1, localhost)
- Blocks link-local, multicast, and reserved IPs
- Webhook settings form now validates before saving
Webhook Security Best Practices:
- Only HTTPS endpoints are accepted
- Webhook receivers should verify X-Signature headers (when implemented)
- Keep webhook endpoint URLs private
- Monitor webhook delivery logs for suspicious activity
What was done:
- Created
static/robots.txtblocking all search engine crawlers - Added
/robots.txtroute inapp.pyto serve with proper headers - Disallows all sensitive paths:
/auth/,/settings/,/cves/, etc. - Applied to all user-agent strings (Google, Bing, etc.)
Additional Protections:
X-Robots-Tag: noindexheader recommended (add to CSP if needed)- Set search engines to avoid indexing via webmaster tools
- Monitor Google Search Console for any indexed pages
What was done:
- Created
.git/hooks/pre-commithook - Prevents accidental commits of
.envand other sensitive files - Blocks patterns:
.env*,*.key,*.pem,credentials.json, etc. - Can be bypassed with
--no-verifyif absolutely necessary (not recommended)
Verification:
# Test the hook by attempting to stage .env
git add .env
git commit -m "test" # Should be blocked
# To commit anyway (avoid unless necessary):
git commit --no-verify # NOT RECOMMENDEDIf .env was pushed to a remote repository before these changes:
# Install if needed: pip install git-filter-repo
# Remove all traces of .env from history
git filter-repo --path .env --invert-paths
# Force push to remote (DANGEROUS — coordinate with team)
git push --force-with-lease# Install: apt-get install bfg (or download from GitHub)
# Remove all traces of .env
bfg --delete-files .env
# Force push
git push --force-with-lease# Interactive rebase to the first commit
git rebase -i --root
# Mark commits that added .env as 'edit'
# Then remove the file and amend: git rm .env && git commit --amend
# Force push
git push --force-with-lease- Notify all team members to re-clone from the cleaned repository
- Rotate all secrets that were exposed (database password, API keys, SECRET_KEY, admin password)
- Check if any secrets were deployed to production and rotate those too
- Update any external services that may have been using the old credentials
- All secrets are unique per environment (dev, staging, production)
-
.envis in.gitignoreand never committed -
SECRET_KEYis at least 32 bytes of random data -
DEFAULT_ADMIN_PASSWORDis at least 12 characters, randomly generated - Database credentials use strong passwords
- NVD API key is registered and valid (or left blank)
- Webhook URL (if configured) is a valid HTTPS public endpoint
- HTTPS is enabled in production (
HTTPS=1in.env) - Session cookies have
Secureflag (requires HTTPS) - CSP headers are applied (already in app.py)
-
robots.txtis served and prevents indexing - Database backups are encrypted and stored securely
- Logs are not exposed publicly and contain no secrets
- Rate limiting is configured for API endpoints
- CSRF protection is enabled (Flask-WTF, already in app.py)
- SQL injection is prevented (SQLAlchemy ORM, already in use)
- XSS is prevented (Jinja2 auto-escaping, already in templates)
- Rotate
SECRET_KEYannually or after any suspected compromise - Rotate
DEFAULT_ADMIN_PASSWORDevery 90 days - Rotate database credentials every 180 days
- Rotate API keys every 12 months
# Check for vulnerabilities in dependencies
pip list --outdated
pip check
# Update all packages
pip install --upgrade -r requirements.txt- Monitor webhook delivery failures (may indicate SSRF attempts)
- Monitor failed login attempts (IP address rate limiting)
- Monitor database query logs for injection attempts
- Monitor file access logs for unauthorized report downloads
If you suspect a compromise:
-
Immediately rotate all secrets
# Generate new ones python -c "import secrets; print(secrets.token_hex(32))"
-
Check git history for exposed files
git log -S "password" --oneline git log -S "api_key" --oneline
-
Clean up if found (use git filter-repo as above)
-
Update CLAUDE.md with incident details and lessons learned
ThreatPilot sets these security headers automatically (in app.py):
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net...
These prevent:
- MIME-type sniffing attacks
- Clickjacking/framing attacks
- Information leakage via Referer
- Unauthorized camera/mic access
If you discover a vulnerability in ThreatPilot:
- Do NOT post it publicly or commit a fix immediately
- Document it with reproduction steps
- Contact the maintainer privately
- Wait for a response before disclosing
- Allow time for patching (typically 30 days)
For this project, consult CLAUDE.md for the current maintainer's contact.
- OWASP Top 10
- Flask Security
- SQLAlchemy ORM Injection Prevention
- NIST Cybersecurity Framework
- CWE: Common Weakness Enumeration
Last Updated: 2026-04-12 Status: All critical vulnerabilities patched