Dorian 39c7ac1924 feat: rootless podman, session hardening, boot stability, sidebar fix
Rootless podman migration (TASK-11):
- Remove sudo from all podman calls in PodmanClient + 8 backend files
- Remove sudo from all podman/docker calls in deploy script
- Restore full systemd security hardening: NoNewPrivileges,
  RestrictAddressFamilies, MemoryDenyWriteExecute, RestrictRealtime,
  RestrictNamespaces, RestrictSUIDSGID, SystemCallFilter, ProtectSystem=strict
- Enable loginctl linger for rootless container persistence
- Remove Ollama from auto-deploy (marketplace-only)

Session & auth hardening:
- Increase MAX_CONCURRENT_SESSIONS 20→50 (prevents eviction storms)
- Debounced 401 redirect in rpc-client.ts (prevents redirect storms)

Boot stability:
- optimize-debian.sh: adds chrony, swap, removes policy-rc.d
- deploy script: pre-restart chrony + swap setup
- ISO build: chrony package, swap file creation
- BootScreen: no longer clears localStorage (prevents splash replay)
- RootRedirect: sole owner of localStorage clearing on server ready

UI fixes:
- Sidebar opacity default changed from 0→visible (fixes missing sidebar
  after page-persistence login without entrance animation)
- Console.log/error wrapped in import.meta.env.DEV guards
- Remove unused route import from RootRedirect

Beta tracking:
- CLAUDE.md: beta freeze protocol added
- MASTER_PLAN.md: TASK-11, TASK-17, phase structure
- BETA-PROGRESS.md: initial tracking doc
- Tagged v1.2.0-alpha.1 as pre-rootless baseline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:53:27 +00:00

65 lines
2.7 KiB
Markdown

## XSS Analysis Complete
Written to `loop/pentest/analysis/xss.md`. Here's the summary:
### 4 Findings
| ID | Type | Location | Confidence |
|---|---|---|---|
| **XSS-001** | DOM-based iframe src injection | `AppSession.vue:399-418``?path=` query param concatenated to iframe src without validation | Medium |
| **XSS-002** | DOM-based javascript: URI redirect | `Login.vue:220,384-386``?redirect=` flows to `window.location.href` in catch handler | Medium |
| **XSS-003** | Cross-origin message injection | `appLauncher.ts:192-284` — NIP-07 postMessage handler has **zero origin validation**, responses sent with `'*'` | **High** |
| **XSS-004** | Weak CSP (amplification) | `nginx-archipelago.conf:20``script-src 'self' 'unsafe-inline'` disables CSP as XSS defense | High |
### Most Critical: XSS-003
The NIP-07 handler is the highest-risk finding. Any iframe (including the external HTTPS apps like botfights.net, nostrudel.ninja, etc.) can silently extract the user's Nostr public key without origin validation. The `contextBroker.ts` handler does this correctly — the `appLauncher.ts` handler does not, and sends responses with wildcard `'*'` origin.
### No Reflected or Stored XSS Found
The codebase is clean on traditional XSS:
- All `v-html` (2 instances) sanitized with DOMPurify
- Stored messages sanitized with HTML entity encoding before storage
- All dynamic content rendered via Vue `{{ }}` auto-escaping
- Backend returns only JSON (serde_json), never raw HTML
- Error messages sanitized by `sanitize_error_message()` before returning
```json
{
"category": "xss",
"findings": [
{
"id": "XSS-001",
"type": "dom_based_xss_iframe_src_injection",
"endpoint": "/app/:appId",
"parameter": "path (query)",
"confidence": "medium",
"payload_suggestion": "/app/indeedhub?path=%23<img+onerror=alert(1)+src=x>"
},
{
"id": "XSS-002",
"type": "dom_based_xss_javascript_uri_redirect",
"endpoint": "/login",
"parameter": "redirect (query)",
"confidence": "medium",
"payload_suggestion": "/login?redirect=javascript:alert(document.cookie)"
},
{
"id": "XSS-003",
"type": "dom_based_cross_origin_message_injection",
"endpoint": "postMessage handler (NIP-07)",
"parameter": "event.data (nostr-request)",
"confidence": "high",
"payload_suggestion": "window.parent.postMessage({type:'nostr-request',id:'1',method:'getPublicKey'},'*')"
},
{
"id": "XSS-004",
"type": "weak_csp_unsafe_inline",
"endpoint": "all pages (nginx)",
"parameter": "n/a",
"confidence": "high",
"payload_suggestion": "n/a - amplification factor, not direct XSS"
}
]
}
```