# Session handoff — next: execute hardening test plan Short handoff. Three new hardening specs landed today; the next session takes the test plan to `left4.me` and runs it. Decision on `2026-05-15-user-uid-split-design.md` is **deferred** until the test plan reports back. ## What just landed Three coordinated specs at `docs/superpowers/specs/`: - `2026-05-15-hardening-threat-model.md` — assets, attackers (A1-A6), trust boundaries (TB1-TB8), attack scenarios (S1-S6), what we defend (D1-D7), what we accept losing. - `2026-05-15-hardening-defenses-survey.md` — full Linux + systemd defense menu, per-defense primitive mapping, candidate composition for `left4me-server@.service` + `left4me-web.service`. - `2026-05-15-hardening-test-plan.md` — 11 tests runnable cold on `left4.me`; drop-in style so they never modify persistent units. ## Why the shape changed (from uid-split → hardening) The prior handoff pointed this session at the 1/2/3-user decision in `2026-05-15-user-uid-split-design.md`. Audit during this session established that the same-uid attack surface (DB readable from srcds, ptrace of gunicorn allowed, RCON passwords stored plaintext in DB, no `/proc` isolation) is closable by *either* a uid split *or* systemd directive composition (`TemporaryFileSystem=` + `SystemCallFilter=~@debug` + `PrivateUsers=true` + `ProcSubset=pid` + empty `CapabilityBoundingSet=`). Operator chose to step back: do threat-model + research + test before committing to either approach. The three new specs are the output of that step-back. ## What's next: run the test plan The test plan is **self-contained** — drop a fresh Claude session on `left4.me` (141.95.32.8) with the spec in hand and it can execute end to end. System units only; no user units, no lingering. Per the test plan's structure: 1. Capture baseline (`systemd-analyze security`, current unit state, sysctl). 2. Tests 1-6 isolate individual directives against srcds on `left4me-server@1` (canary; server@2 stays baseline as a fallback). 3. Test 7 composes everything that passed. 4. Test 8 verifies the threat-model defenses (D1-D5) actually work. 5. Test 9 applies `kernel.yama.ptrace_scope=2` system-wide. 6. Test 10 applies the sudo-compatible subset to `left4me-web.service`. 7. Test 11 is a 24-48h soak. Results template at the bottom of the test plan; fill in as you go. After execution: write the implementation plan at `docs/superpowers/plans/2026-MM-DD-hardening-refactor.md` against the proven composition. The plan touches `~/Projekte/ckn-bw/bundles/left4me/metadata.py` (live source for unit emission per `items.py:2-5`) and the reference copies in `deploy/files/usr/local/lib/systemd/system/`. ## Decision-relevant context - **Source of truth for unit files is ckn-bw**, not left4me's `deploy/files/`. The `deploy/files/usr/local/lib/systemd/system/*.service` copies are reference-only post-deploy-dir-rethink; the `systemd/units` reactor in `~/Projekte/ckn-bw/bundles/left4me/metadata.py:150+` is the live emission. Audit confirmed (commit `5284e28` + `items.py:2-5` comment). - **Sandbox is already strong.** `l4d2-sandbox` unit is not in scope for this refactor — its hardening profile was verified during 2026-05-15 build-time-idmap work. Document as load-bearing; do not weaken. - **Sudo on the web app blocks deep hardening there.** `NoNewPrivileges=true` and `PrivateUsers=true` are incompatible with the helper-invocation pattern. Sudo-compatible subset only on web. Full hardening blocked on a future "replace sudo with systemctl-managed unit triggering" refactor (build-overlay-unit spec is a step in that direction). - **uid-split spec is deferred, not closed.** After Phase A test results come back, decide: residual risk small enough → close `2026-05-15-user-uid-split-design.md` as superseded. Residual risk significant → write the split as a follow-up. ## Open questions to clarify with operator before/during execution (Captured in the threat model's "Open questions" section.) 1. Is gunicorn directly internet-reachable, or only via nginx? 2. Admin-auth strength on the web app (defines S2 realism). 3. Workshop content curation policy (defines A3 realism). 4. Is `ckn@10.0.4.128` usable as a test bench, or is `left4.me` the only deployment target? (Test plan currently assumes `left4.me`.) 5. Current `kernel.yama.ptrace_scope` setting on the host. 6. AppArmor enabled on host? (Default Debian: not enabled.) ## What's NOT next - **build-overlay-unit refactor** (`docs/superpowers/specs/2026-05-15-build-overlay-unit-design.md`). Still queued; sequenced behind this. The hardening profile from this work becomes the template for the build-overlay unit. - **Pushing the ckn-bw `91b7265` commit.** Still unpushed; still safe. Mentioned in the previous handoff; not a blocker. - **uid-split implementation.** Deferred pending test results. - **AppArmor profiles.** Listed in the defenses survey; deferred. Revisit after Phase A if directive-only hardening leaves gaps. ## Pointers - Test plan (the thing to execute): `docs/superpowers/specs/2026-05-15-hardening-test-plan.md` - Threat model: `docs/superpowers/specs/2026-05-15-hardening-threat-model.md` - Defenses survey: `docs/superpowers/specs/2026-05-15-hardening-defenses-survey.md` - Original uid-split spec (deferred): `docs/superpowers/specs/2026-05-15-user-uid-split-design.md` - Live unit emission: `~/Projekte/ckn-bw/bundles/left4me/metadata.py:150+` - Reference units: `deploy/files/usr/local/lib/systemd/system/` - Scratch plan from earlier this session (`~/.claude/plans/docs-superpowers-specs-2026-05-15-sessio-cosmic-codd.md`) is superseded by the three specs; safe to discard.