# Security Advisory: XSS in Leaflet bindPopup() — CVE-2025-69993
## Overview
| Field | Value |
|-------|-------|
| **CVE ID** | CVE-2025-69993 |
| **Affected Software** | [Leaflet](https://leafletjs.com/) |
| **Affected Versions** | <= 1.9.4 |
| **Vulnerability Type** | Cross-Site Scripting (XSS) |
| **CWE** | [CWE-79](https://cwe.mitre.org/data/definitions/79.html) — Improper Neutralization of Input During Web Page Generation |
| **CVSS 3.1 Score** | 6.1 (Medium) |
| **CVSS 3.1 Vector** | `CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N` |
| **Discoverer** | Pierfrancesco Conti |
## Description
Leaflet versions up to and including 1.9.4 are vulnerable to Cross-Site Scripting (XSS) through the `bindPopup()` method. This method renders user-supplied input as raw HTML without any sanitization, allowing attackers to inject and execute arbitrary JavaScript code in the context of a victim's browser session.
The vulnerability is exploitable when applications pass user-controlled data to `bindPopup()` — a common pattern in web mapping applications that allow users to create or annotate map markers.
## Affected Code
The `bindPopup()` method accepts and renders arbitrary HTML by default:
```javascript
L.marker([lat, lng])
.addTo(map)
.bindPopup(userControlledContent) // No sanitization applied
.openPopup();
```
The same issue affects `bindTooltip()` and any other Leaflet method that renders user-supplied HTML content.
## Proof of Concept
A full Angular application demonstrating the vulnerability is included in the `leaflet-xss-poc/` directory. The app simulates a realistic scenario: a web mapping application where users can create markers with custom descriptions.
### Environment
- **Framework:** Angular 21 (standalone components)
- **Library:** Leaflet 1.9.4
- **Browsers tested:** Chromium-based (Chrome, Edge) and Firefox
### How to Run the POC
```bash
cd leaflet-xss-poc
npm install
npm start
```
Then open `http://localhost:4200` in a browser.
### Steps to Reproduce
1. Open the application in a browser
2. In the **Description** textarea, enter the following payload:
```
Test
```
3. Click **"Add Marker"**
4. The popup opens automatically on the map — the injected JavaScript executes (an alert dialog appears)
### Vulnerable Code Path
The user input from the form (`popupDescription`) is passed directly to Leaflet's `bindPopup()` without any sanitization:
```typescript
// app.ts — line 56-58
this.currentMarker = L.marker([this.markerLat, this.markerLng])
.addTo(this.map)
.bindPopup(popupContent) // popupContent = user input, no sanitization
.openPopup();
```
The template collects user input via a standard Angular form:
```html
```
### Additional Test Payloads
The following payloads were tested successfully:
| Payload | Result |
|---------|--------|
| `` | JavaScript execution via error handler |
| `