Download security_headers.py from wuhp/vulnscan: direct link, hf CLI and curl.
- Browser
- Download file 9.34 kB
-
https://huggingface.co/spaces/wuhp/vulnscan/resolve/main/security_headers.py
- Command line
-
hf download hf://spaces/wuhp/vulnscan/security_headers.py
-
curl -L -o security_headers.py https://huggingface.co/spaces/wuhp/vulnscan/resolve/main/security_headers.py
9.34 kB
| """ | |
| 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 |