CVE-2019-25084: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: A vulnerability, which was classified as problematic, has been found in Hide Files on GitHub up to 2.x. This issue affects the function addEventListener of the file extension/options.js. The manipulation leads to cross site scripting. The attack may be initiated remotely. Upgrading to version 3.0.0 is able to address this issue. The name of the patch is 9de0c57df81db1178e0e79431d462f6d9842742e. It is recommended to upgrade the affected component. The associated identifier of this vulnerability is VDB-216767.
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: 2022-12-25T18:15Z
Repository: https://github.com/sindresorhus/hide-files-on-github
Language: JavaScript
Files changed: extension/api.js, extension/options.js
Commit date: 2019-03-19 23:15:26 +0700
Commit message: Avoid self-XSS (#73)


Diff: diff --git a/extension/api.js b/extension/api.js
index 8c79ef8..418b080 100644
--- a/extension/api.js
+++ b/extension/api.js
@@ -34,5 +34,22 @@ HideFilesOnGitHub.storage = {
 	}),
 	set: object => {
 		chrome.storage.sync.set(object);
 	}
 };
+
+// Inlined partial `escape-goat` package
+const escapeHTML = input => input
+	.replace(/&/g, '&amp;')
+	.replace(/"/g, '&quot;')
+	.replace(/'/g, '&#39;')
+	.replace(/</g, '&lt;')
+	.replace(/>/g, '&gt;');
+
+window.escapeTag = (input, ...parts) => {
+	let output = input[0];
+	for (let i = 0; i < parts.length; i++) {
+		output = output + escapeHTML(parts[i]) + input[i + 1];
+	}
+
+	return output;
+};
diff --git a/extension/options.js b/extension/options.js
index f8be082..8bc90b4 100644
--- a/extension/options.js
+++ b/extension/options.js
@@ -1,6 +1,6 @@
-/* global HideFilesOnGitHub */
+/* global HideFilesOnGitHub, escapeTag */
 'use strict';
 const regexField = document.querySelector('#hideRegExp');
 const errorMessage = document.querySelector('#errorMessage');
 const delimiters = /^\/|\/$/;
 
@@ -9,18 +9,18 @@ document.addEventListener('input', update);
 document.addEventListener('change', update);
 
 /* Native validation tooltips don't seem to work */
 function setValidity(text = '') {
 	errorMessage.innerHTML = text;
-	regexField.setCustomValidity(text); /* Triggers :invalid */
+	regexField.setCustomValidity(errorMessage.textContent); /* Triggers :invalid */
 }
 
 function update() {
 	for (const line of regexField.value.split('\n')) {
 		// Don't allow delimiters in RegExp string
 		if (delimiters.test(line)) {
-			return setValidity(`Use <code>${line.replace(/^\/|\/$/g, '')}</code> instead of <code>${line}</code>. Slashes are not required.`);
+			return setValidity(escapeTag`Use <code>${line.replace(/^\/|\/$/g, '')}</code> instead of <code>${line}</code>. Slashes are not required.`);
 		}
 
 		// Fully test each RegExp
 		try {
 			// eslint-disable-next-line no-new

Vulnerable code: /* global HideFilesOnGitHub */
	regexField.setCustomValidity(text); /* Triggers :invalid */
			return setValidity(`Use <code>${line.replace(/^\/|\/$/g, '')}</code> instead of <code>${line}</code>. Slashes are not required.`);
Fixed code: 
// Inlined partial `escape-goat` package
const escapeHTML = input => input
	.replace(/&/g, '&amp;')
	.replace(/"/g, '&quot;')
	.replace(/'/g, '&#39;')
	.replace(/</g, '&lt;')
	.replace(/>/g, '&gt;');

window.escapeTag = (input, ...parts) => {
	let output = input[0];
	for (let i = 0; i < parts.length; i++) {
		output = output + escapeHTML(parts[i]) + input[i + 1];
	}

	return output;
};
/* global HideFilesOnGitHub, escapeTag */
	regexField.setCustomValidity(errorMessage.textContent); /* Triggers :invalid */
			return setValidity(escapeTag`Use <code>${line.replace(/^\/|\/$/g, '')}</code> instead of <code>${line}</code>. Slashes are not required.`);