Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
externalized today, so a stricter policy would need that rewritten first.
Defense-in-depth: this would have limited the blast radius of the retune
XSS above (and any future/residual one) even before that fix landed.
- **CSP now allows `blob:` workers, fixing a blank Tab View / Staff View
render.** The baseline CSP added above (#47) covered
`script-src`/`style-src`/`img-src`/`font-src`/`media-src`/`connect-src`
but never set `worker-src`. Per CSP fallback rules, a worker without an
explicit `worker-src` falls back to `script-src`'s policy, which allows
`'self'`/`'unsafe-inline'`/`https:` but not `blob:` — and alphaTab (used
by the `tabview` and `staffview` plugins) spawns its rendering worker
from a `blob:` URL. Without `worker-src`, browsers silently blocked that
worker, rendering a blank canvas for every song. Added
`worker-src 'self' blob:;`, matching the `blob:` allowance already
granted to `img-src`/`media-src` for the same plugin-CDN-asset reason.

### Fixed

Expand Down
1 change: 1 addition & 0 deletions server.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
"img-src 'self' data: blob: https:; "
"font-src 'self' data: https:; "
"media-src 'self' blob: https:; "
"worker-src 'self' blob:; "
Comment thread
carochacs marked this conversation as resolved.
Comment thread
carochacs marked this conversation as resolved.
"connect-src 'self' https: wss: ws:; "
"object-src 'none'; "
"base-uri 'self'; "
Expand Down
15 changes: 15 additions & 0 deletions tests/test_security_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@ def test_csp_blocks_non_https_script_origins_but_allows_self_and_https(client):
assert "*" not in script_src


def test_csp_allows_self_and_blob_workers(client):
# alphaTab (tabview/staffview) spawns its rendering worker from a blob:
# URL. Without an explicit worker-src, CSP falls back to script-src,
# which allows 'self'/https: but not blob: -- silently blocking the
# worker and rendering a blank canvas (issue: worker-src missing after
# the #44/#47 baseline-CSP addition).
r = client.get("/api/version")
csp = r.headers["Content-Security-Policy"]
worker_src = next(part for part in csp.split(";") if part.strip().startswith("worker-src"))
assert "'self'" in worker_src
assert "blob:" in worker_src
assert "http:" not in worker_src
assert "data:" not in worker_src


def test_security_headers_present_on_error_responses_too(client):
# A 404 (unknown route) must still carry the headers — they're set via
# middleware wrapping the whole call_next chain, not per-route.
Expand Down
Loading