A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live
I2151
A page served beside the write routes runs only script it shipped, and a rebinding host reads nothing
Where it stands
devtask.issue- Readiness
- complete completion is recorded and every required evidence token is present
- Status
- DONE
- Can start
- not now
- Milestone
- Milestone status
- ACTIVE
- Wave
0- Waiting on
- none
- Holds back
- none
- Behind it in all
0- Evidence
3of3
Moves
plan.transitionWhat it is
- Objective
- Give /swagger the Cockpit's security headers and integrity-checked scripts, refuse a GET whose Host names another server, and escape script-breaking sequences where the site embeds JSON.
- Why
- /swagger serves no Content-Security-Policy, no frame-ancestors and no subresource integrity for the scripts it loads from unpkg (apps/majordomus-cli/src/http/swagger.rs:52,79; headers confirmed live by the sub-audit), on the same origin as every POST route. The Origin check (apps/majordomus-cli/src/http/router.rs:503-508, 718-745) passes for a same-origin script, so a substituted CDN script could call plan/transition, continuity/*, recover/orphans or executions/start. GET routes do no Host validation (only non-GET is checked, apps/majordomus-cli/src/http/router.rs:504, host_is_literal at :749), and the comment at apps/majordomus-cli/src/http/router.rs:498-502 assumes a cross-origin read is contained, which DNS rebinding defeats (the exploit is unverified). The static site embeds json_encode | safe inside script elements without escaping the closing sequence (site/templates/partials/graph.html:76, site/templates/api.html:94, site/templates/why-section.html:284; exploitability unverified). The Cockpit already sends a CSP (apps/majordomus-cli/src/cockpit/mod.rs:193-204, 296-310). Baseline audit of 2026-10-09 at master 1fb8d6be44, projections gaps 7 and 11, lifecycle authorization row and drift 9.
- Now
- /swagger trusts a CDN with the write routes' origin; GET answers any Host; three site templates embed JSON unescaped.
- Wanted
- /swagger is served with its own Content-Security-Policy (the pinned unpkg files and the one inline script by digest, frame-ancestors none, no eval) plus nosniff and no-referrer, and both CDN files carry sha384 integrity; a request from loopback whose Host is neither an address nor localhost is refused 403 forbidden before any surface answers (a rebinding page reads nothing), while a request from another host may name this machine as it knows it; the three site templates replace </ with <\/ before marking JSON safe. Verified in Chromium: /swagger renders 53 operation groups with no console error and no CSP violation.
- Done when
- unknown: the record declares no `completion`
- Risk
- unknown: the record declares no `risk`
Acceptance
- GET /swagger answers with a Content-Security-Policy that includes frame-ancestors, and every script it loads carries an integrity attribute
- A GET whose Host header names another domain is refused before its handler runs
- A site data value containing a closing script tag renders as text in each template that embeds JSON
- Validation
bin/majordomus plan validatecargo test --test http_host --test http_serveMJ_TEST_JOBS=4 bash test/run.sh <the case this issue adds>- Evidence required
swagger_csp_testrebinding_host_refused_testsite_script_escape_case- Evidence present
site_script_escape_caserebinding_host_refused_testswagger_csp_test
Scope
- Touches
apps/majordomus-cli/src/http/swagger.rsapps/majordomus-cli/src/http/router.rsapps/majordomus-cli/src/cockpit/mod.rssite/templates/partials/graph.htmlsite/templates/api.htmlsite/templates/why-section.htmlapps/majordomus-cli/tests/http_host.rsapps/majordomus-cli/tests/http_serve.rstest/casesdocs/MCP.md- Not
- unknown: the record declares no `non_scope`
- Depends on
- none
- Priority
- p0
- Profile
- implementation
- Parallel safe
- false
- Owner
- unknown: the record declares no `owner`
The work so far
- Branches
- none
- Merged
- none
- Commits
0- Trunk
- master
- Sessions
- none
- Created
- 2026-10-09
- Updated
- 2026-10-14T22:17:04Z
- Started
- 2026-10-14T22:16:25Z
- Verified
- 2026-10-14T22:16:45Z
- Completed
- 2026-10-14T22:17:04Z
Synchronisation
- Adapter
scripts/github-sync- Repository
- unknown: the derived plan's header carries no repository
- External issue
- unknown: a live GitHub state; this executable makes no network call, so only `scripts/github-sync --check` can answer it
- State there
- unknown: a live GitHub state; this executable makes no network call, so only `scripts/github-sync --check` can answer it
Findings
Nothing is wrong with these records.