CVE-2023-37299: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Joplin before 2.11.5 allows XSS via an AREA element of an image map.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2023-06-30T15:15Z
Repository: https://github.com/laurent22/joplin
Language: HTML
Files changed: packages/app-cli/tests/md_to_html/sanitize_15.html, packages/app-cli/tests/md_to_html/sanitize_16.html, packages/app-cli/tests/md_to_html/sanitize_16.md, packages/renderer/htmlUtils.ts
Commit date: 2023-05-19 11:00:31 +0100
Commit message: All: Security: Prevent XSS by sanitizing certain HTML attributes

Diff: diff --git a/packages/app-cli/tests/md_to_html/sanitize_15.html b/packages/app-cli/tests/md_to_html/sanitize_15.html
index d6d42d0761..e322e708e1 100644
--- a/packages/app-cli/tests/md_to_html/sanitize_15.html
+++ b/packages/app-cli/tests/md_to_html/sanitize_15.html
@@ -1 +1 @@
-<use href="data:image/svg+xml,&lt;svg id=&apos;x&apos; xmlns=&apos;http://www.w3.org/2000/svg&apos;&gt;&lt;image href=&apos;asdf&apos; onerror=&apos;top.require(`child_process`).execSync(`calc.exe`)&apos; /&gt;&lt;/svg&gt;#x" class="jop-noMdConv">
\ No newline at end of file
+<use href="#" class="jop-noMdConv">
\ No newline at end of file
diff --git a/packages/app-cli/tests/md_to_html/sanitize_16.html b/packages/app-cli/tests/md_to_html/sanitize_16.html
new file mode 100644
index 0000000000..e6cc433c1c
--- /dev/null
+++ b/packages/app-cli/tests/md_to_html/sanitize_16.html
@@ -0,0 +1 @@
+<map name="test" class="jop-noMdConv"><area coords="0,0,1000,1000" href="#" class="jop-noMdConv"/></map><img usemap="#test" src="https://github.com/Ry0taK.png" class="jop-noMdConv"/>
\ No newline at end of file
diff --git a/packages/app-cli/tests/md_to_html/sanitize_16.md b/packages/app-cli/tests/md_to_html/sanitize_16.md
new file mode 100644
index 0000000000..931e2e1eae
--- /dev/null
+++ b/packages/app-cli/tests/md_to_html/sanitize_16.md
@@ -0,0 +1 @@
+<map name="test"><area coords="0,0,1000,1000" href="javascript:top.require(`child_process`).execSync(`calc.exe`)"></map><img usemap="#test" src="https://github.com/Ry0taK.png">
\ No newline at end of file
diff --git a/packages/renderer/htmlUtils.ts b/packages/renderer/htmlUtils.ts
index 33da16c700..45644682ec 100644
--- a/packages/renderer/htmlUtils.ts
+++ b/packages/renderer/htmlUtils.ts
@@ -231,22 +231,22 @@ class HtmlUtils {
 					if (attrName.length <= 2) continue;
 					if (attrName.substr(0, 2) !== 'on') continue;
 					delete attrs[attrName];
 				}
 
-				if (name === 'a') {
-					// Make sure that only non-acceptable URLs are filtered out.
-					// In particular we want to exclude `javascript:` URLs.
-					if ('href' in attrs && !this.isAcceptedUrl(attrs['href'])) {
-						attrs['href'] = '#';
-					}
+				// Make sure that only non-acceptable URLs are filtered out. In
+				// particular we want to exclude `javascript:` URLs. This
+				// applies to A tags, and also AREA ones but to be safe we don't
+				// filter on the tag name and process all HREF attributes.
+				if ('href' in attrs && !this.isAcceptedUrl(attrs['href'])) {
+					attrs['href'] = '#';
+				}
 
-					// We need to clear any such attribute, otherwise it will
-					// make any arbitrary link open within the application.
-					if ('data-from-md' in attrs) {
-						delete attrs['data-from-md'];
-					}
+				// We need to clear any such attribute, otherwise it will
+				// make any arbitrary link open within the application.
+				if ('data-from-md' in attrs) {
+					delete attrs['data-from-md'];
 				}
 
 				if (options.addNoMdConvClass) {
 					let classAttr = attrs['class'] || '';
 					if (!classAttr.includes('jop-noMdConv')) {

Vulnerable code: <use href="data:image/svg+xml,&lt;svg id=&apos;x&apos; xmlns=&apos;http://www.w3.org/2000/svg&apos;&gt;&lt;image href=&apos;asdf&apos; onerror=&apos;top.require(`child_process`).execSync(`calc.exe`)&apos; /&gt;&lt;/svg&gt;#x" class="jop-noMdConv">
				if (name === 'a') {
					// Make sure that only non-acceptable URLs are filtered out.
					// In particular we want to exclude `javascript:` URLs.
					if ('href' in attrs && !this.isAcceptedUrl(attrs['href'])) {
						attrs['href'] = '#';
					}
					// We need to clear any such attribute, otherwise it will
					// make any arbitrary link open within the application.
					if ('data-from-md' in attrs) {
						delete attrs['data-from-md'];
					}
Fixed code: <use href="#" class="jop-noMdConv">
<map name="test" class="jop-noMdConv"><area coords="0,0,1000,1000" href="#" class="jop-noMdConv"/></map><img usemap="#test" src="https://github.com/Ry0taK.png" class="jop-noMdConv"/>
<map name="test"><area coords="0,0,1000,1000" href="javascript:top.require(`child_process`).execSync(`calc.exe`)"></map><img usemap="#test" src="https://github.com/Ry0taK.png">
				// Make sure that only non-acceptable URLs are filtered out. In
				// particular we want to exclude `javascript:` URLs. This
				// applies to A tags, and also AREA ones but to be safe we don't
				// filter on the tag name and process all HREF attributes.
				if ('href' in attrs && !this.isAcceptedUrl(attrs['href'])) {
					attrs['href'] = '#';
				}
				// We need to clear any such attribute, otherwise it will
				// make any arbitrary link open within the application.
				if ('data-from-md' in attrs) {
					delete attrs['data-from-md'];