mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-07-13 02:38:50 +00:00
f15b677981
## This PR fixes the stored XSS in full (closes #1536) Mesh-advertised node names (`adv_name`) and observer names were rendered into the dashboard DOM **without HTML-escaping** in multiple places — the same class as the publicly disclosed MeshCore dashboard XSS (CVE-2026-45323). `adv_name` has no protocol-level validation and the Go `sanitizeName()` keeps `< > " &`, so a payload like `<img src=x onerror=...>` reaches the frontend intact and executes. **I audited every name/sender/text/channel render in `public/` and this PR escapes all unescaped sinks. There are no known remaining XSS sinks of this class after this change.** ### Sinks fixed (all escaped via the existing global `escapeHtml`, plus a local helper for the standalone `area-map.html`) | File | Sink | |------|------| | `app.js` | global search dropdown — node name + channel name | | `nodes.js` | nodes-table row name; node-detail Leaflet popups (×2) | | `observers.js` | observers-table name cell | | `packets.js` | observer-name cells via `obsNameOnly` (×4) + observer multi-select checkbox label | | `live.js` | node-filter `<option>` + map marker tooltip | | `analytics.js` | topology map node tooltip | | `route-view.js` | hop + union marker tooltips (×2) | | `area-map.html` | node popups (×2) — added a local `escapeHtml` (file is standalone) | ### Already-safe (verified, not changed) `map.js` popups (`safeEsc`), live-feed text (`escapeHtml(preview)`), packet-detail text, channel messages (`channels.js`), `route-render.js` popups, `hop-display.js`. ### Why escape at the sink (not the backend) `sanitizeName()` only strips control chars; HTML-escaping stored names server-side would be lossy and corrupt legitimate names containing `& < >`, and break the `meshcore://` deep-links / exports. Output-encoding at render is the correct OWASP fix and matches `meshcore-card` v0.3.3. ### Tests - Added 6 `escapeHtml` regression tests including the CVE payload `<img src=x onerror=alert(1)>` and an attribute-breakout payload. - `node test-frontend-helpers.js`: **568 passed / 32 failed** — the 32 are pre-existing sandbox limitations (e.g. `AreaFilter is not defined`), identical to the untouched baseline (562/32). Zero new failures. ### Cache busting Automatic — the server rewrites `__BUST__` in `index.html` with a restart timestamp, so no manual bump is needed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: CoreScope Bot <bot@meshcore> Co-authored-by: Kpa-clawbot <bot@clawbot.local>