#!/usr/bin/env python3 """Security headers audit for FlaskPaste. Verifies all required security headers are present and correctly configured. """ import sys sys.path.insert(0, ".") from app import create_app # Required headers and their expected values REQUIRED_HEADERS = { "X-Content-Type-Options": "nosniff", "X-Frame-Options": "DENY", "Content-Security-Policy": "default-src 'none'", "Referrer-Policy": "strict-origin-when-cross-origin", "Permissions-Policy": "geolocation=(), microphone=(), camera=()", "Cache-Control": "no-store, no-cache, must-revalidate", "Pragma": "no-cache", } # Headers that should NOT be present FORBIDDEN_HEADERS = [ "X-Powered-By", "Server", ] # Endpoints to test TEST_ENDPOINTS = [ ("/", "GET", 200), ("/health", "GET", 200), ("/challenge", "GET", 200), ("/nonexistent", "GET", 400), # Error response ] def run_audit(): """Run security headers audit.""" print("=" * 60) print("SECURITY HEADERS AUDIT") print("=" * 60) app = create_app("testing") client = app.test_client() results = {"passed": 0, "failed": 0, "warnings": 0} for endpoint, method, _expected_status in TEST_ENDPOINTS: print(f"\n[{method} {endpoint}]") print("-" * 40) if method == "GET": resp = client.get(endpoint) elif method == "POST": resp = client.post(endpoint, data=b"test") else: continue # Check required headers for header, expected in REQUIRED_HEADERS.items(): actual = resp.headers.get(header, "") if expected in actual: print(f" ✓ {header}") results["passed"] += 1 else: print(f" ✗ {header}") print(f" Expected: {expected}") print(f" Got: {actual or '(missing)'}") results["failed"] += 1 # Check forbidden headers for header in FORBIDDEN_HEADERS: if header in resp.headers: print(f" ⚠ {header} should not be present") results["warnings"] += 1 else: print(f" ✓ No {header} header") results["passed"] += 1 # Check X-Request-ID if "X-Request-ID" in resp.headers: print(" ✓ X-Request-ID present") results["passed"] += 1 else: print(" ✗ X-Request-ID missing") results["failed"] += 1 # Summary print("\n" + "=" * 60) print("SUMMARY") print("=" * 60) print(f" Passed: {results['passed']}") print(f" Failed: {results['failed']}") print(f" Warnings: {results['warnings']}") total = results["passed"] + results["failed"] if results["failed"] == 0: print(f"\n{results['passed']}/{total} checks passed") return 0 else: print(f"\nFAILED: {results['failed']}/{total} checks failed") return 1 if __name__ == "__main__": sys.exit(run_audit())