""" Security Header Analyzer ========================= Detects missing or misconfigured HTTP security headers and cookies. OWASP: A02, A05 (2021) """ import httpx from base import Finding, Severity, VulnerabilityPlugin HEADER_CHECKS = { "Content-Security-Policy": { "severity": Severity.MEDIUM, "description": "No Content-Security-Policy header found. This allows XSS attacks to load arbitrary scripts from any origin.", "owasp": "A05:2021 - Security Misconfiguration", "cwe": "CWE-693", "remediation": "Add a restrictive CSP:\nContent-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'", "cvss": 6.1, "tags": ["headers", "csp", "xss"], }, "Strict-Transport-Security": { "severity": Severity.HIGH, "description": "Missing HSTS header. Browsers may connect over plain HTTP, enabling man-in-the-middle attacks and cookie theft.", "owasp": "A02:2021 - Cryptographic Failures", "cwe": "CWE-319", "remediation": "Add: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload", "cvss": 7.4, "tags": ["headers", "hsts", "tls"], }, "X-Frame-Options": { "severity": Severity.MEDIUM, "description": "Missing X-Frame-Options allows the page to be embedded in an iframe — enabling clickjacking attacks.", "owasp": "A05:2021 - Security Misconfiguration", "cwe": "CWE-1021", "remediation": "Add: X-Frame-Options: DENY\nOr use CSP: Content-Security-Policy: frame-ancestors 'none'", "cvss": 4.3, "tags": ["headers", "clickjacking"], }, "X-Content-Type-Options": { "severity": Severity.LOW, "description": "Missing X-Content-Type-Options allows MIME-type sniffing, which can enable content injection attacks.", "owasp": "A05:2021 - Security Misconfiguration", "cwe": "CWE-16", "remediation": "Add: X-Content-Type-Options: nosniff", "cvss": 3.7, "tags": ["headers", "mime-sniffing"], }, "Referrer-Policy": { "severity": Severity.LOW, "description": "No Referrer-Policy set. Sensitive URL parameters may leak to third parties via the Referer header.", "owasp": "A05:2021 - Security Misconfiguration", "cwe": "CWE-116", "remediation": "Add: Referrer-Policy: strict-origin-when-cross-origin", "cvss": 3.1, "tags": ["headers", "privacy"], }, "Permissions-Policy": { "severity": Severity.LOW, "description": "No Permissions-Policy header. Browser features like camera, microphone, and geolocation are unrestricted.", "owasp": "A05:2021 - Security Misconfiguration", "cwe": "CWE-16", "remediation": "Add: Permissions-Policy: geolocation=(), microphone=(), camera=()", "cvss": 2.6, "tags": ["headers", "permissions"], }, "Cross-Origin-Opener-Policy": { "severity": Severity.LOW, "description": "Missing COOP header. The page can be opened by cross-origin pages enabling XS-Leaks attacks.", "owasp": "A05:2021 - Security Misconfiguration", "cwe": "CWE-346", "remediation": "Add: Cross-Origin-Opener-Policy: same-origin", "cvss": 3.1, "tags": ["headers", "cors", "xs-leaks"], }, "Cross-Origin-Resource-Policy": { "severity": Severity.LOW, "description": "Missing CORP header allows cross-origin sites to embed this resource, enabling side-channel attacks.", "owasp": "A05:2021 - Security Misconfiguration", "cwe": "CWE-346", "remediation": "Add: Cross-Origin-Resource-Policy: same-origin", "cvss": 3.1, "tags": ["headers", "cors"], }, } WEAK_CSP_PATTERNS = [ ("unsafe-inline", 5.4), ("unsafe-eval", 5.4), ("data:", 4.3), ("*", 6.1), ("http:", 4.3), ] INSECURE_COOKIE_FLAGS = { "HttpOnly": ("Cookie readable by JavaScript — XSS can steal session tokens", Severity.MEDIUM, 4.3), "Secure": ("Cookie sent over plain HTTP — susceptible to interception", Severity.MEDIUM, 5.4), "SameSite": ("Missing SameSite attribute — vulnerable to CSRF attacks", Severity.LOW, 4.3), } SERVER_LEAKS = { "server": "Server header reveals web server software and version — aids fingerprinting", "x-powered-by": "X-Powered-By header reveals backend technology stack", "x-aspnet-version": "X-AspNet-Version header reveals .NET version in use", "x-aspnetmvc-version": "X-AspNetMvc-Version reveals ASP.NET MVC version", } class SecurityHeaderPlugin(VulnerabilityPlugin): name = "security_headers" description = "Checks for missing/misconfigured security headers, weak CSP, insecure cookies, and server info leaks" async def run(self, target: str) -> list[Finding]: findings: list[Finding] = [] try: r = await self.client.get(target.rstrip("/"), timeout=12, follow_redirects=True) except Exception: return [] headers_lower = {k.lower(): v for k, v in r.headers.items()} # ── Required security headers ────────────────────────────────────────── for header, cfg in HEADER_CHECKS.items(): if header.lower() not in headers_lower: findings.append(Finding( plugin=self.name, title=f"Missing {header}", severity=cfg["severity"], description=cfg["description"], evidence={"header": header, "present": False}, owasp=cfg["owasp"], cwe=cfg["cwe"], remediation=cfg["remediation"], endpoint=target, cvss_estimate=cfg["cvss"], tags=cfg["tags"], )) # ── Weak CSP directives ──────────────────────────────────────────────── csp = headers_lower.get("content-security-policy", "") if csp: for pattern, cvss in WEAK_CSP_PATTERNS: if pattern in csp: findings.append(Finding( plugin=self.name, title=f"Weak CSP: '{pattern}' directive present", severity=Severity.MEDIUM, description=f"The Content-Security-Policy contains '{pattern}' which significantly weakens XSS protection.", evidence={"csp_value": csp, "weak_directive": pattern}, owasp="A05:2021 - Security Misconfiguration", cwe="CWE-1021", remediation=f"Remove '{pattern}' from your CSP. Use nonces or hashes for inline scripts.", endpoint=target, cvss_estimate=cvss, tags=["headers", "csp", "xss"], )) # ── Insecure cookies ─────────────────────────────────────────────────── for cookie_header in r.headers.get_list("set-cookie"): cookie_name = cookie_header.split("=")[0].strip() for flag, (desc, sev, cvss) in INSECURE_COOKIE_FLAGS.items(): if flag.lower() not in cookie_header.lower(): findings.append(Finding( plugin=self.name, title=f"Insecure cookie: missing {flag}", severity=sev, description=f"Cookie '{cookie_name}': {desc}", evidence={"cookie_name": cookie_name, "raw": cookie_header, "missing_flag": flag}, owasp="A05:2021 - Security Misconfiguration", cwe="CWE-614", remediation=f"Set the {flag} flag on all session and auth cookies.", endpoint=target, cvss_estimate=cvss, tags=["cookies", "session"], )) # ── Server info leakage ──────────────────────────────────────────────── for leak_header, desc in SERVER_LEAKS.items(): val = headers_lower.get(leak_header) if val: findings.append(Finding( plugin=self.name, title=f"Server information disclosure: {leak_header}", severity=Severity.LOW, description=desc, evidence={"header": leak_header, "value": val}, owasp="A05:2021 - Security Misconfiguration", cwe="CWE-200", remediation=f"Remove or suppress the '{leak_header}' response header in your web server config.", endpoint=target, cvss_estimate=3.1, tags=["headers", "information-disclosure", "fingerprinting"], )) return findings