Coverage for open_webui/utils/security_headers.py: 25%
81 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 05:07 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 05:07 +0000
1import os
2import re
3from typing import Dict
6def set_security_headers() -> Dict[str, str]:
7 """
8 Sets security headers based on environment variables.
10 This function reads specific environment variables and uses their values
11 to set corresponding security headers. The headers that can be set are:
12 - cache-control
13 - permissions-policy
14 - strict-transport-security
15 - referrer-policy
16 - x-content-type-options
17 - x-download-options
18 - x-frame-options
19 - x-permitted-cross-domain-policies
20 - content-security-policy
21 - content-security-policy-report-only
22 - cross-origin-embedder-policy
23 - cross-origin-opener-policy
24 - cross-origin-resource-policy
25 - reporting-endpoints
27 Each environment variable is associated with a specific setter function
28 that constructs the header. If the environment variable is set, the
29 corresponding header is added to the options dictionary.
31 Returns:
32 dict: A dictionary containing the security headers and their values.
33 """
34 options = {}
35 header_setters = {
36 'CACHE_CONTROL': set_cache_control,
37 'HSTS': set_hsts,
38 'PERMISSIONS_POLICY': set_permissions_policy,
39 'REFERRER_POLICY': set_referrer,
40 'XCONTENT_TYPE': set_xcontent_type,
41 'XDOWNLOAD_OPTIONS': set_xdownload_options,
42 'XFRAME_OPTIONS': set_xframe,
43 'XPERMITTED_CROSS_DOMAIN_POLICIES': set_xpermitted_cross_domain_policies,
44 'CONTENT_SECURITY_POLICY': set_content_security_policy,
45 'CONTENT_SECURITY_POLICY_REPORT_ONLY': set_content_security_policy_report_only,
46 'CROSS_ORIGIN_EMBEDDER_POLICY': set_cross_origin_embedder_policy,
47 'CROSS_ORIGIN_OPENER_POLICY': set_cross_origin_opener_policy,
48 'CROSS_ORIGIN_RESOURCE_POLICY': set_cross_origin_resource_policy,
49 'REPORTING_ENDPOINTS': set_reporting_endpoints,
50 }
52 for env_var, setter in header_setters.items():
53 value = os.environ.get(env_var, None)
54 if value: 54 ↛ 55line 54 didn't jump to line 55 because the condition on line 54 was never true
55 header = setter(value)
56 if header:
57 options.update(header)
59 return options
62# Set HTTP Strict Transport Security(HSTS) response header
63def set_hsts(value: str):
64 pattern = r'^max-age=(\d+)(;includeSubDomains)?(;preload)?$'
65 match = re.match(pattern, value, re.IGNORECASE)
66 if not match:
67 value = 'max-age=31536000;includeSubDomains'
68 return {'Strict-Transport-Security': value}
71# Set X-Frame-Options response header
72def set_xframe(value: str):
73 pattern = r'^(DENY|SAMEORIGIN)$'
74 match = re.match(pattern, value, re.IGNORECASE)
75 if not match:
76 value = 'DENY'
77 return {'X-Frame-Options': value}
80# Set Permissions-Policy response header
81def set_permissions_policy(value: str):
82 pattern = r'^(?:(accelerometer|autoplay|camera|clipboard-read|clipboard-write|fullscreen|geolocation|gyroscope|magnetometer|microphone|midi|payment|picture-in-picture|sync-xhr|usb|xr-spatial-tracking)=\((self)?\),?)*$'
83 match = re.match(pattern, value, re.IGNORECASE)
84 if not match:
85 value = 'none'
86 return {'Permissions-Policy': value}
89# Set Referrer-Policy response header
90def set_referrer(value: str):
91 pattern = r'^(no-referrer|no-referrer-when-downgrade|origin|origin-when-cross-origin|same-origin|strict-origin|strict-origin-when-cross-origin|unsafe-url)$'
92 match = re.match(pattern, value, re.IGNORECASE)
93 if not match:
94 value = 'no-referrer'
95 return {'Referrer-Policy': value}
98# Set Cache-Control response header
99def set_cache_control(value: str):
100 pattern = r'^(public|private|no-cache|no-store|must-revalidate|proxy-revalidate|max-age=\d+|s-maxage=\d+|no-transform|immutable)(,\s*(public|private|no-cache|no-store|must-revalidate|proxy-revalidate|max-age=\d+|s-maxage=\d+|no-transform|immutable))*$'
101 match = re.match(pattern, value, re.IGNORECASE)
102 if not match:
103 value = 'no-store, max-age=0'
105 return {'Cache-Control': value}
108# Set X-Download-Options response header
109def set_xdownload_options(value: str):
110 if value != 'noopen':
111 value = 'noopen'
112 return {'X-Download-Options': value}
115# Set X-Content-Type-Options response header
116def set_xcontent_type(value: str):
117 if value != 'nosniff':
118 value = 'nosniff'
119 return {'X-Content-Type-Options': value}
122# Set X-Permitted-Cross-Domain-Policies response header
123def set_xpermitted_cross_domain_policies(value: str):
124 pattern = r'^(none|master-only|by-content-type|by-ftp-filename)$'
125 match = re.match(pattern, value, re.IGNORECASE)
126 if not match:
127 value = 'none'
128 return {'X-Permitted-Cross-Domain-Policies': value}
131# Set Content-Security-Policy response header
132def set_content_security_policy(value: str):
133 return {'Content-Security-Policy': value}
136# Set Content-Security-Policy-Report-Only response header
137def set_content_security_policy_report_only(value: str):
138 return {'Content-Security-Policy-Report-Only': value}
141# Set Cross-Origin-Embedder-Policy response header
142def set_cross_origin_embedder_policy(value: str):
143 pattern = r'^(unsafe-none|require-corp|credentialless)$'
144 match = re.match(pattern, value, re.IGNORECASE)
145 if not match:
146 value = 'require-corp'
147 return {'Cross-Origin-Embedder-Policy': value}
150# Set Cross-Origin-Opener-Policy response header
151def set_cross_origin_opener_policy(value: str):
152 pattern = r'^(unsafe-none|same-origin-allow-popups|same-origin)$'
153 match = re.match(pattern, value, re.IGNORECASE)
154 if not match:
155 value = 'same-origin'
156 return {'Cross-Origin-Opener-Policy': value}
159# Set Cross-Origin-Resource-Policy response header
160def set_cross_origin_resource_policy(value: str):
161 pattern = r'^(same-site|same-origin|cross-origin)$'
162 match = re.match(pattern, value, re.IGNORECASE)
163 if not match:
164 value = 'same-origin'
165 return {'Cross-Origin-Resource-Policy': value}
168# Set Reporting-Endpoints response header
169def set_reporting_endpoints(value: str):
170 return {'Reporting-Endpoints': value}