Private
Public Access
1
0

fix(ws): add Origin allowlist to browser WebSocket upgrade (CSWSH hardening)

Closes Draco-Lunaris/Linux-Patch-Manager#10

The browser WebSocket endpoint at GET /api/v1/ws/jobs previously
authenticated solely via a single-use, 60-second ticket passed as a query
parameter. A leaked ticket (browser history, Referer, proxy logs, support
bundles) could be redeemed from any origin, enabling Cross-Site WebSocket
Hijacking (CSWSH).

This change adds a second gate: the Origin header must match an explicit
allowlist. The check runs BEFORE ticket validation so that rejected
cross-origin probes do not consume the legitimate users ticket.

Changes:
- pm-core: new security.allowed_origins config field; default derived
  from sso_callback_url; startup warning if both are unparseable
- pm-web: ws_handler extracts HeaderMap and calls check_origin first;
  returns 403 on missing/malformed/disallowed origins
- config: documented allowed_origins key in config.example.toml
- docs: security-review.md section 1.4 (WebSocket Origin Allowlist)
- tests: 40 unit tests (7 pm-core, 33 pm-web)
This commit is contained in:
Draco Lunaris
2026-06-02 10:45:38 -05:00
parent 80709d48a7
commit ed5df26140
8 changed files with 925 additions and 12 deletions

14
Cargo.lock generated
View File

@ -2521,7 +2521,7 @@ dependencies = [
[[package]]
name = "pm-agent-client"
version = "0.1.8"
version = "0.1.9"
dependencies = [
"anyhow",
"chrono",
@ -2538,7 +2538,7 @@ dependencies = [
[[package]]
name = "pm-auth"
version = "0.1.8"
version = "0.1.9"
dependencies = [
"anyhow",
"argon2",
@ -2565,7 +2565,7 @@ dependencies = [
[[package]]
name = "pm-ca"
version = "0.1.8"
version = "0.1.9"
dependencies = [
"anyhow",
"chrono",
@ -2588,7 +2588,7 @@ dependencies = [
[[package]]
name = "pm-core"
version = "0.1.8"
version = "0.1.9"
dependencies = [
"aes-gcm",
"anyhow",
@ -2612,7 +2612,7 @@ dependencies = [
[[package]]
name = "pm-reports"
version = "0.1.8"
version = "0.1.9"
dependencies = [
"anyhow",
"chrono",
@ -2632,7 +2632,7 @@ dependencies = [
[[package]]
name = "pm-web"
version = "0.1.8"
version = "0.1.9"
dependencies = [
"anyhow",
"axum",
@ -2672,7 +2672,7 @@ dependencies = [
[[package]]
name = "pm-worker"
version = "0.1.8"
version = "0.1.9"
dependencies = [
"anyhow",
"chrono",