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>
2.7 KiB
2.7 KiB
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
{
"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"
}
]
}