Statement on CVE-2025-69993 (XSS via `bindPopup`)
A recent CVE, CVE-2025-69993, claims Leaflet is vulnerable to Cross-Site Scripting because bindPopup() renders its string argument as HTML without sanitization. We are publishing this pinned issue to clarify our position, because the CVE has caused confusion in downstream security audits.
Our position
This is documented, intentional behavior, not a vulnerability in Leaflet.
bindPopup(), bindTooltip(), setContent() and related methods are documented to accept an HTML string, a DOM element, or a function, and to render the string as HTML. In the scenario described by the CVE, the underlying issue (CWE-79) lies with the calling application that passes attacker-controlled input into a documented HTML sink without sanitizing it. A lightweight front-end mapping library cannot, and should not, bundle a heavy HTML sanitizer to defend against application-level misuse of a documented API.
Prior art
This pattern — a documented API that renders HTML, with sanitization treated as the application's responsibility — is the established norm across the JavaScript ecosystem:
- MapLibre GL JS (the most direct peer to Leaflet) documents
Popup.setHTML()as: "This method does not perform HTML filtering or sanitization, and must be used only with trusted content." It provides a separatesetText()method for untrusted input. The same applies to Mapbox GL JS. - React ships
dangerouslySetInnerHTML— the name itself is the warning. - Vue ships
v-htmlwith the explicit guidance: "Never use v-html on user-provided content." - jQuery's
.html()setsinnerHTMLand has been the subject of multiple disputed CVEs over the years on these exact grounds. - D3.js's
selection.html()setsinnerHTMLdirectly, with no security warning in the official documentation. - lit-html ships an explicit
unsafeHTMLdirective — again named to signal the contract.
None of these libraries bundles an HTML sanitizer. All treat the boundary between "content the application asked us to render" and "untrusted input the application should have sanitized" as the application's responsibility. Leaflet's bindPopup sits squarely in this same category.
What we have done
To remove any ambiguity, we have updated the API documentation and tutorials. The reference now states explicitly at every relevant entry point (bindPopup, bindTooltip, setContent, openPopup, openTooltip, setPopupContent, setTooltipContent, and the content option) that string content is rendered as HTML, and recommends sanitizing untrusted input with a library like DOMPurify or passing a DOM element built with textContent. The Popup, Tooltip, GeoJSON, and Quick Start documentation pages now include a security note with a safe-pattern code sample. These changes apply to both the 1.x and 2.0 docs on leafletjs.com.
What we have not done, and will not do
- We will not bundle a sanitizer into Leaflet. The right tool (DOMPurify, sanitize-html, Trusted Types, a CSP, etc.) depends on the application's threat model and content policy.
- We will not silently break existing applications that intentionally rely on HTML rendering for links, formatting, images, and similar.
A separate, longer-term design discussion about adopting Trusted Types in a future major version is tracked independently and is not driven by this CVE.
What to do if your scanner flags this CVE
- Audit whether your application actually passes untrusted input into Leaflet's popup/tooltip APIs. If it doesn't, the CVE does not apply to you.
- If it does, sanitize the input or use the DOM-element pattern documented in the Popup reference. This is the correct fix regardless of which library renders the HTML.
- Link your security team to this issue as the maintainers' formal position.
CVE dispute
We have formally disputed this CVE with MITRE and requested it be marked DISPUTED in the CVE record. We will update this issue when MITRE responds.
— The Leaflet maintainers
Source: Leaflet/Leaflet