Summary
SecurityHeadersMiddleware._DEFAULT_CSP (and the dev override in dev_csp(...)) doesn't set a worker-src directive, and CSP's fallback chain uses script-src for workers. Because script-src is 'self' 'unsafe-inline' 'unsafe-eval' (without blob:), every dependency that creates a Web Worker via URL.createObjectURL(blob) is blocked.
Repro
Mount any maplibre-gl map in a page rendered through the framework. The browser logs:
Refused to create a worker from 'blob:http://localhost:8001/<uuid>' because it
violates the following Content Security Policy directive: "script-src 'self'
'unsafe-inline' 'unsafe-eval' http://localhost:5051". Note that 'worker-src' was
not explicitly set, so 'script-src' is used as a fallback.
The map mounts but never paints (the worker handles tile decoding and source updates).
This isn't MapLibre-specific. Any library that ships a worker bundled as a blob (most modern WASM/canvas libs — comlink, web-tree-sitter, parquet-wasm, lighthouse-style, etc.) will hit the same wall.
Expected
The default CSP should add:
worker-src 'self' blob:
child-src 'self' blob:
(child-src is the legacy fallback some browser versions still consult before worker-src.)
blob: for workers is widely accepted as safe even in fairly strict CSPs — the bytes still come from same-origin code that already had script-execution privileges.
Workaround
from simple_module_hosting.middleware import SecurityHeadersMiddleware
_EXTRA = "worker-src 'self' blob:; child-src 'self' blob:"
SecurityHeadersMiddleware._DEFAULT_CSP = SecurityHeadersMiddleware._DEFAULT_CSP + "; " + _EXTRA
_orig_dev = SecurityHeadersMiddleware.dev_csp
SecurityHeadersMiddleware.dev_csp = staticmethod(
lambda url: _orig_dev(url) + "; " + _EXTRA
)
Has to run before create_app(settings). Monkey-patching the framework's middleware class isn't a great pattern for app code.
Acceptance
- Loading a maplibre-gl map (or any blob-worker library) in an unmodified host scaffold renders without CSP violations.
Summary
SecurityHeadersMiddleware._DEFAULT_CSP(and the dev override indev_csp(...)) doesn't set aworker-srcdirective, and CSP's fallback chain usesscript-srcfor workers. Becausescript-srcis'self' 'unsafe-inline' 'unsafe-eval'(withoutblob:), every dependency that creates a Web Worker viaURL.createObjectURL(blob)is blocked.Repro
Mount any maplibre-gl map in a page rendered through the framework. The browser logs:
The map mounts but never paints (the worker handles tile decoding and source updates).
This isn't MapLibre-specific. Any library that ships a worker bundled as a blob (most modern WASM/canvas libs — comlink, web-tree-sitter, parquet-wasm, lighthouse-style, etc.) will hit the same wall.
Expected
The default CSP should add:
(
child-srcis the legacy fallback some browser versions still consult beforeworker-src.)blob:for workers is widely accepted as safe even in fairly strict CSPs — the bytes still come from same-origin code that already had script-execution privileges.Workaround
Has to run before
create_app(settings). Monkey-patching the framework's middleware class isn't a great pattern for app code.Acceptance