diff --git a/app/assets/javascripts/users_select/index.js b/app/assets/javascripts/users_select/index.js
index 8ed92e6b948de10afe88243331183a4217a545bb..656c851aa3d3666c55682b106243a11f53c08f98 100644
--- a/app/assets/javascripts/users_select/index.js
+++ b/app/assets/javascripts/users_select/index.js
@@ -210,7 +210,7 @@ function UsersSelect(currentUser, els, options = {}) {
return axios.put(issueURL, data).then(({ data }) => {
let user = {};
- let tooltipTitle = user.name;
+ let tooltipTitle;
$dropdown.trigger('loaded.gl.dropdown');
$loading.addClass('gl-display-none');
if (data.assignee) {
@@ -806,7 +806,9 @@ UsersSelect.prototype.renderRow = function (
${
username
- ? ``
+ ? ``
: ''
}
${this.renderApprovalRules(elsClassName, user.applicable_approval_rules)}
diff --git a/spec/frontend/users_select/index_spec.js b/spec/frontend/users_select/index_spec.js
index 0d2aae7894499319fbaa5851b132ba94340fd314..3757e63c4f96274a6a40d175d0fe51865d602721 100644
--- a/spec/frontend/users_select/index_spec.js
+++ b/spec/frontend/users_select/index_spec.js
@@ -108,4 +108,39 @@ describe('~/users_select/index', () => {
});
});
});
+
+ describe('XSS', () => {
+ const escaped = '><script>alert(1)</script>';
+ const issuableType = 'merge_request';
+ const user = {
+ availability: 'not_set',
+ can_merge: true,
+ name: 'name',
+ };
+ const selected = true;
+ const username = 'username';
+ const img = '
';
+ const elsClassName = 'elsclass';
+
+ it.each`
+ prop | val | element
+ ${'username'} | ${'>'} | ${'.dropdown-menu-user-username'}
+ ${'name'} | ${'>'} | ${'.dropdown-menu-user-full-name'}
+ `('properly escapes the $prop $val', ({ prop, val, element }) => {
+ const u = prop === 'username' ? val : username;
+ const n = prop === 'name' ? val : user.name;
+ const row = UsersSelect.prototype.renderRow(
+ issuableType,
+ { ...user, name: n },
+ selected,
+ u,
+ img,
+ elsClassName,
+ );
+ const fragment = document.createRange().createContextualFragment(row);
+ const output = fragment.querySelector(element).innerHTML.trim();
+
+ expect(output).toBe(escaped);
+ });
+ });
});