This document provides detailed information about each security header analyzer, including what the header does, how it's evaluated, severity levels, and configuration options.
Module: sha/analyzers/hsts.py
Purpose:
Forces browsers to only communicate with the server over HTTPS, preventing protocol downgrade attacks and cookie hijacking.
How It Works:
- Analyzes the
max-agedirective (minimum 10886400 seconds / 126 days required) - Checks for
includeSubDomainsdirective - Detects
preloaddirective
Severity Levels:
- Missing: CRITICAL
- Bad configuration: CRITICAL
- Good configuration: INFO
Good Values:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Strict-Transport-Security: max-age=63072000
Bad Values:
Strict-Transport-Security: max-age=300 (too short)
References:
Module: sha/analyzers/xframe.py
Purpose:
Prevents clickjacking attacks by controlling whether the page can be framed.
How It Works:
- Checks for DENY or SAMEORIGIN directives
- Detects deprecated ALLOW-FROM directive
Severity Levels:
- Missing: HIGH
- DENY: INFO (best)
- SAMEORIGIN: INFO (good)
- ALLOW-FROM: HIGH (deprecated)
Good Values:
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
References:
Module: sha/analyzers/content_type.py
Purpose:
Prevents MIME-sniffing attacks by forcing browsers to respect declared Content-Type.
How It Works:
- Checks for
nosniffdirective
Severity Levels:
- Missing: MEDIUM-HIGH
- Present: INFO
Good Values:
X-Content-Type-Options: nosniff
Module: sha/analyzers/csp.py
Purpose: Mitigates XSS and data injection attacks by controlling which resources can be loaded.
How It Works:
- Parses CSP directives
- Detects
unsafe-inlineandunsafe-eval - Checks for wildcard sources (
*) - Validates nonce/hash usage
- Detects
strict-dynamic - NEW: Detects 12 common CSP bypass patterns:
- JSONP endpoints (Google APIs, AngularJS CDN, AWS S3, Cloudflare, etc.)
- Angular/AngularJS template injection vulnerabilities
- User-uploaded content domains
- Missing
base-uri(allows base tag injection) - Missing/permissive
object-src(Flash/plugin bypass) script-src 'self'with file upload capability (stored XSS)unsafe-hasheswithout proper contextdata:URIs inscript-srcscript-src-elemwithoutscript-src- Dangling markup injection via
img-src
Severity Levels:
- Missing: CRITICAL
- Contains unsafe-inline or unsafe-eval: HIGH
- HIGH severity bypasses (JSONP, data URIs, Angular): HIGH
- Wildcard sources: MEDIUM-HIGH
- LOW/MEDIUM severity bypasses (base-uri, object-src): Recommendations only
- Good configuration: INFO
Good Values:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-xyz'; base-uri 'self'; object-src 'none'
Content-Security-Policy: default-src 'none'; script-src 'strict-dynamic' 'nonce-xyz'; base-uri 'none'
Bad Values:
Content-Security-Policy: default-src *
Content-Security-Policy: script-src 'unsafe-inline'
Content-Security-Policy: script-src 'self' https://ajax.googleapis.com (JSONP bypass)
Content-Security-Policy: script-src 'self' data: (data URI bypass)
Common Bypasses Detected:
# JSONP bypass via Google APIs
Content-Security-Policy: script-src 'self' https://accounts.google.com
# Angular template injection
Content-Security-Policy: script-src 'self' https://ajax.googleapis.com/ajax/libs/angularjs/
# AWS S3 JSONP endpoints
Content-Security-Policy: script-src 'self' https://mybucket.s3.amazonaws.com
# Missing base-uri (recommended in addition to script-src)
Content-Security-Policy: script-src 'self' 'nonce-xyz'
Module: sha/analyzers/referrer_policy.py
Purpose:
Controls how much referrer information is sent with requests.
How It Works:
- Evaluates policy strictness
- Recommends stricter policies when appropriate
Severity Levels:
- Missing: HIGH
- Unsafe values: HIGH
- Good values: INFO
Good Values:
Referrer-Policy: no-referrer
Referrer-Policy: strict-origin-when-cross-origin
Referrer-Policy: same-origin
Bad Values:
Referrer-Policy: unsafe-url
Referrer-Policy: origin
Module: sha/analyzers/permissions_policy.py
Purpose:
Controls which browser features and APIs can be used.
How It Works:
- Parses feature directives
- Validates allowlist syntax
- Checks for sensible defaults
Severity Levels:
- Missing: LOW
- Present: INFO
Good Values:
Permissions-Policy: geolocation=(), microphone=(), camera=()
Permissions-Policy: payment=(self)
Module: sha/analyzers/coep.py
Purpose:
Enables cross-origin isolation, protecting against Spectre attacks.
How It Works:
- Checks for
require-corporcredentialless
Severity Levels:
- Missing: LOW
- Present: INFO
Good Values:
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Embedder-Policy: credentialless
Module: sha/analyzers/coop.py
Purpose:
Isolates browsing context from cross-origin windows.
How It Works:
- Checks for isolation level
same-originis strongest
Severity Levels:
- Missing: LOW
- Present: INFO
Good Values:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin-allow-popups
Module: sha/analyzers/corp.py
Purpose:
Controls which origins can load the resource.
How It Works:
- Validates policy value
Severity Levels:
- Missing: LOW
- Present: INFO
Good Values:
Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Resource-Policy: same-site
Cross-Origin-Resource-Policy: cross-origin
Module: sha/analyzers/x_xss_protection.py
Purpose: Legacy header that controlled browser XSS filters in Internet Explorer, Chrome, and Safari. Now deprecated. Modern recommendation is to explicitly disable it or rely on Content-Security-Policy.
How It Works:
- Checks for value
0(explicitly disabled - recommended) - Detects
1; mode=block(legacy acceptable) - Flags
1alone as bad (creates vulnerabilities)
Severity Levels:
- Missing: LOW
- Value
0: INFO (best) - Value
1; mode=block: ACCEPTABLE (legacy) - Value
1: BAD (medium severity) - Unknown values: BAD
Good Values:
X-XSS-Protection: 0
Acceptable Values:
X-XSS-Protection: 1; mode=block
Bad Values:
X-XSS-Protection: 1
References:
Module: sha/analyzers/x_download_options.py
Purpose: Internet Explorer 8+ specific header that prevents the browser from executing downloaded HTML files in the context of the site, preventing Same Origin Policy violations.
How It Works:
- Checks for
noopenvalue - Any other value is flagged as bad
Severity Levels:
- Missing: LOW
- Value
noopen: INFO - Other values: BAD (low severity)
Good Values:
X-Download-Options: noopen
References:
Module: sha/analyzers/x_permitted_cross_domain_policies.py
Purpose: Controls whether Adobe Flash Player, Adobe Acrobat, or PDF documents can load cross-domain policy files from the web server. Prevents untrusted Flash/PDF content from accessing site data.
How It Works:
- Checks for
none(best - completely prohibits policy files) - Detects
master-only(acceptable - allows only /crossdomain.xml) - Flags permissive values:
all,by-content-type,by-ftp-filename
Severity Levels:
- Missing: MEDIUM
- Value
none: INFO (best) - Value
master-only: ACCEPTABLE (low severity) - Value
all: BAD (high severity) - Values
by-content-type,by-ftp-filename: BAD (medium severity) - Unknown values: BAD (medium severity)
Good Values:
X-Permitted-Cross-Domain-Policies: none
Acceptable Values:
X-Permitted-Cross-Domain-Policies: master-only
Bad Values:
X-Permitted-Cross-Domain-Policies: all
X-Permitted-Cross-Domain-Policies: by-content-type
X-Permitted-Cross-Domain-Policies: by-ftp-filename
References:
Module: sha/analyzers/set_cookie.py
Purpose: Analyzes cookie security attributes to prevent session hijacking, XSS cookie theft, and CSRF attacks. Validates that cookies include proper security directives.
How It Works:
- Validates Secure, HttpOnly, and SameSite attributes
- NEW: Validates cookie prefix constraints (__Secure-, __Host-)
- NEW: Analyzes Domain/Path scope for overly broad configurations
- NEW: Detects sensitive cookies (session/auth) with missing security
- NEW: Warns about excessive SameSite=None usage (third-party cookies)
- Handles multiple Set-Cookie headers
- Provides aggregate analysis across all cookies
Severity Levels:
- Missing Secure or HttpOnly: HIGH
- Missing SameSite or SameSite=None without Secure: MEDIUM
- Prefix violations (__Secure-/__Host- constraints): HIGH
- Sensitive cookie without security attributes: HIGH
- Overly broad Domain scope (e.g., "com"): MEDIUM
- Domain with leading dot or Path=/ on sensitive cookies: LOW (recommendation only)
- Good configuration: INFO
Good Values:
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/
Set-Cookie: __Host-session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/
Set-Cookie: __Secure-token=xyz; Secure; HttpOnly; SameSite=Lax
Bad Values:
Set-Cookie: session=abc123
Set-Cookie: __Secure-session=abc123; HttpOnly; SameSite=Strict (missing Secure - violates prefix)
Set-Cookie: __Host-session=abc123; Secure; HttpOnly; Domain=example.com (has Domain - violates prefix)
Set-Cookie: PHPSESSID=xyz (sensitive cookie, no security attributes)
Set-Cookie: tracking=123; Secure; HttpOnly; SameSite=None; Domain=com (overly broad domain)
Cookie Prefix Validation (RFC 6265bis):
__Secure-prefix requires:- Secure attribute
__Host-prefix requires:- Secure attribute
- No Domain attribute
- Path=/ or omitted
Scope Analysis:
- Detects Domain with leading dot (applies to all subdomains)
- Detects overly broad domains (e.g., "com", "co.uk")
- Warns when sensitive cookies have Path=/ (exposed to entire site)
Sensitive Cookie Detection: Detects cookies that appear to contain sensitive data based on name patterns:
- Session identifiers: session, sess, sid, jsessionid, phpsessid
- Authentication: auth, token, jwt, bearer, access, refresh
- User identifiers: user, uid, userid
- CSRF tokens: csrf, xsrf
SameSite=None Frequency Warning:
- Triggers when ≥50% of cookies use SameSite=None
- Warns about third-party cookie privacy risks
- Recommends evaluating necessity of cross-site cookie access
References:
Module: sha/analyzers/cache_control.py
Purpose: Controls caching behavior to prevent sensitive data leakage through browser and proxy caches. Ensures that sensitive pages (login forms, account details, personal data) are not cached where unauthorized parties could access them.
How It Works:
- Parses Cache-Control directives (no-store, no-cache, must-revalidate, private, public, max-age)
- NEW: Detects directive conflicts (mutually exclusive or redundant combinations)
- NEW: Validates must-revalidate usage for long cache durations
- NEW: Supports stale-while-revalidate and stale-if-error directives
- Evaluates appropriateness for sensitive vs. static content
Severity Levels:
- Missing (for sensitive pages): MEDIUM
- Directive conflicts (public+private, no-store+max-age): MEDIUM (conflicts trigger BAD status)
- Long max-age without must-revalidate: LOW (recommendation only)
- Good configuration: INFO
Good Values (Sensitive Pages):
Cache-Control: no-store, no-cache, must-revalidate, private
Cache-Control: no-store, private
Good Values (Static Resources):
Cache-Control: public, max-age=31536000, immutable
Cache-Control: public, max-age=604800, must-revalidate
Acceptable Values:
Cache-Control: private, max-age=0
Cache-Control: max-age=604800 (without must-revalidate - gets recommendation)
Bad Values:
Cache-Control: public, max-age=86400 (for sensitive data)
Cache-Control: public, private (mutually exclusive - CONFLICT)
Cache-Control: no-store, max-age=3600 (max-age redundant with no-store - CONFLICT)
Cache-Control: no-store, no-cache (no-cache redundant with no-store - CONFLICT)
Cache-Control: private, s-maxage=3600 (s-maxage inapplicable with private - CONFLICT)
Directive Conflicts Detected:
-
public + private (Mutually Exclusive) - MEDIUM severity
Cache-Control: public, private # Recommendation: Remove either 'public' or 'private' - use 'private' for sensitive data -
no-store + max-age (Redundant) - LOW severity
Cache-Control: no-store, max-age=3600 # Recommendation: Remove 'max-age' - 'no-store' already prevents caching -
no-store + no-cache (Redundant) - LOW severity
Cache-Control: no-store, no-cache # Recommendation: Remove 'no-cache' - 'no-store' is stronger -
private + s-maxage (Inapplicable) - LOW severity
Cache-Control: private, s-maxage=3600 # Recommendation: Remove 's-maxage' - only applies to shared caches, inapplicable with 'private'
must-revalidate Validation:
Warns when long cache durations (>1 day) are used without must-revalidate or immutable:
Cache-Control: max-age=604800 (7 days)
# Recommendation: Consider adding 'must-revalidate' to prevent serving stale content if origin is unreachable
This prevents browsers from serving very stale content when the origin server is unreachable.
Modern Stale- Directives:*
Supports RFC 5861 stale-while-revalidate and stale-if-error:
Cache-Control: max-age=600, stale-while-revalidate=30
Cache-Control: max-age=600, stale-if-error=86400
These directives enable graceful degradation by allowing slightly stale content to be served while revalidating in the background.
Common Use Cases:
| Content Type | Recommended Configuration |
|---|---|
| Login pages | no-store, private |
| Account pages | no-store, no-cache, must-revalidate, private |
| API responses (sensitive) | no-store, private |
| Static assets (versioned) | public, max-age=31536000, immutable |
| Static assets (unversioned) | public, max-age=3600, must-revalidate |
| Dynamic content (public) | public, max-age=60, must-revalidate |
References:
- MDN: Cache-Control
- RFC 7234: HTTP Caching
- RFC 5861: HTTP stale-while-revalidate
- OWASP: Session Management Cheat Sheet
Module: sha/analyzers/cross_origin_validator.py
Purpose: Validates the interaction between Cross-Origin-Embedder-Policy (COEP) and Cross-Origin-Opener-Policy (COOP) headers to determine if the site enables cross-origin isolation, which is required for using SharedArrayBuffer and high-resolution timers.
How It Works:
- This is a cross-header validator that analyzes COEP and COOP together
- Only generates a finding when at least one of COEP or COOP is present
- Detects full isolation (COEP: require-corp + COOP: same-origin)
- Detects credentialless isolation (COEP: credentialless + COOP: same-origin)
- Detects partial isolation (only one header set, or incompatible values)
- Detects incompatible combinations
Severity Levels:
- Full/credentialless isolation: INFO (GOOD status)
- Partial isolation: MEDIUM (BAD status)
- Incompatible combinations: MEDIUM (BAD status)
Full Isolation (GOOD):
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
Enables SharedArrayBuffer with strict CORP requirement on all subresources.
Credentialless Isolation (GOOD with recommendation):
Cross-Origin-Embedder-Policy: credentialless
Cross-Origin-Opener-Policy: same-origin
Enables SharedArrayBuffer by loading cross-origin resources without credentials.
Partial Isolation Examples (BAD):
# COEP set but COOP missing
Cross-Origin-Embedder-Policy: require-corp
(no COOP header)
# Result: SharedArrayBuffer NOT available
# COOP set but wrong value
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin-allow-popups
# Result: SharedArrayBuffer NOT available
# COOP set but COEP missing
Cross-Origin-Opener-Policy: same-origin
(no COEP header)
# Result: SharedArrayBuffer NOT available
Incompatible Combinations (BAD):
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: unsafe-none
# Wrong COOP value
Key Points:
- This validator complements the individual COEP, COOP, and CORP analyzers
- Individual analyzers check header syntax and values
- This validator checks cross-header interactions
- Only appears when COEP or COOP headers are present
- Provides actionable recommendations for achieving isolation
References:
- MDN: Cross-Origin Isolation
- web.dev: COOP and COEP
- See individual header docs: COEP, COOP
- CRITICAL: Immediate security risk (currently unused)
- HIGH: Significant security vulnerability
- MEDIUM-HIGH: Important security improvement
- MEDIUM: Recommended security enhancement
- LOW: Nice-to-have security feature
- INFO: Properly configured (no action needed)
Each analyzer follows this structure:
CONFIG = {
"display_name": "Header-Name",
"severity_missing": "high",
"description": "What this header does",
"validation": {
"good": ["list", "of", "good", "values"],
"acceptable": ["acceptable", "values"],
"bad": ["unsafe", "values"]
},
"messages": {
"good": "Message for good configuration",
"acceptable": "Message for acceptable configuration",
"bad": "Message for bad configuration",
"missing": "Message when header is missing"
},
"recommendations": {
"missing": "How to add the header",
"bad": "How to fix bad configuration"
}
}