## 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" }, { "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" } ] } ```