VYPR
Moderate severityNVD Advisory· Published Jan 31, 2023· Updated Mar 27, 2025

CVE-2022-45598

CVE-2022-45598

Description

Cross Site Scripting vulnerability in Joplin Desktop App before v2.9.17 allows attacker to execute arbitrary code via improper santization.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

CVE-2022-45598: Stored XSS in Joplin Desktop App before v2.9.17 allows arbitrary code execution via crafted strings in code block language identifiers.

Vulnerability

Overview CVE-2022-45598 is a stored cross-site scripting (XSS) vulnerability in the Joplin Desktop App prior to version 2.9.17. The root cause lies in improper sanitization of the language identifier used in Markdown fenced code blocks. When rendering notes to HTML, Joplin's MdToHtml module directly interpolates the user-supplied language string into inline attributes (data-joplin-language) without escaping HTML entities, allowing an attacker to inject arbitrary HTML/JavaScript [1][3].

Exploitation

Prerequisites and Attack Surface An attacker can exploit this vulnerability by crafting a note containing a specially constructed fenced code block. The exploitation does not require authentication beyond the ability to create or import notes (e.g., via the Evernote import feature). The crafted payload is embedded in the language tag of the code fence, such as: ``"><svg/onload=top.eval(atob("..."))>``. When the note is viewed or rendered, the attacker-controlled string is placed into a context where HTML attributes are not escaped, leading to execution of the JavaScript payload [2][3].

Impact

The successful injection allows arbitrary JavaScript execution within the context of the Joplin application's renderer process. As demonstrated in the fix commit, the provided payload leverages top.eval() to execute a decoded command, which on macOS spawns the Calculator app via child_process. This illustrates potential for arbitrary code execution (ACE) on the host system beyond typical XSS sandbox restrictions, significantly increasing the severity of the bug [3].

Mitigation

The vulnerability was addressed in commit a2de167b95debad83a0f0c7925a88c0198db812e and released in version 2.9.17. The fix uses the html-entities library to properly encode the language string before inserting it into the HTML output, preventing attribute injection. Users are strongly advised to upgrade to Joplin Desktop App v2.9.17 or later [2][4].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
joplinnpm
< 2.9.172.9.17

Affected products

2
  • Joplin/Joplin Desktop Appdescription
  • ghsa-coords
    Range: < 2.9.17

Patches

1
a2de167b95de

All: Security: Fix XSS when a specially crafted string is passed to the renderer

https://github.com/laurent22/joplinLaurent CozicNov 14, 2022via ghsa
3 files changed · +7 1
  • packages/app-cli/tests/md_to_html/sanitize_12.html+1 0 added
    @@ -0,0 +1 @@
    +<div class="joplin-editable"><pre class="joplin-source" data-joplin-language="&quot;&gt;&lt;svg/onload=top.eval(atob(&quot;cmVxdWlyZSgnY2hpbGRfcHJvY2VzcycpLmV4ZWMoJ29wZW4gLW4gL1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvcicp&quot;))&gt;" data-joplin-source-open="```&quot;&gt;&lt;svg/onload=top.eval(atob(&quot;cmVxdWlyZSgnY2hpbGRfcHJvY2VzcycpLmV4ZWMoJ29wZW4gLW4gL1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvcicp&quot;))&gt;&#10;" data-joplin-source-close="&#10;```">ts</pre><pre class="hljs"><code><span class="hljs-attribute">ts</span></code></pre></div>
    
  • packages/app-cli/tests/md_to_html/sanitize_12.md+3 0 added
    @@ -0,0 +1,3 @@
    +```"><svg/onload=top.eval(atob("cmVxdWlyZSgnY2hpbGRfcHJvY2VzcycpLmV4ZWMoJ29wZW4gLW4gL1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvcicp"))>
    +ts
    +```
    
  • packages/renderer/MdToHtml.ts+3 1 modified
    @@ -8,6 +8,8 @@ import { RenderResult, RenderResultPluginAsset } from './MarkupToHtml';
     import { Options as NoteStyleOptions } from './noteStyle';
     import hljs from './highlight';
     
    +const Entities = require('html-entities').AllHtmlEntities;
    +const htmlentities = new Entities().encode;
     const MarkdownIt = require('markdown-it');
     const md5 = require('md5');
     
    @@ -482,7 +484,7 @@ export default class MdToHtml {
     				// The strings includes the last \n that is part of the fence,
     				// so we remove it because we need the exact code in the source block
     				const trimmedStr = this.removeLastNewLine(str);
    -				const sourceBlockHtml = `<pre class="joplin-source" data-joplin-language="${lang}" data-joplin-source-open="\`\`\`${lang}&#10;" data-joplin-source-close="&#10;\`\`\`">${markdownIt.utils.escapeHtml(trimmedStr)}</pre>`;
    +				const sourceBlockHtml = `<pre class="joplin-source" data-joplin-language="${htmlentities(lang)}" data-joplin-source-open="\`\`\`${htmlentities(lang)}&#10;" data-joplin-source-close="&#10;\`\`\`">${markdownIt.utils.escapeHtml(trimmedStr)}</pre>`;
     
     				if (this.shouldSkipHighlighting(trimmedStr, lang)) {
     					outputCodeHtml = markdownIt.utils.escapeHtml(trimmedStr);
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.