diff options
author | Steve Azzopardi <sazzopardi@gitlab.com> | 2018-11-18 11:01:48 +0000 |
---|---|---|
committer | Steve Azzopardi <steveazz@outlook.com> | 2018-11-18 12:12:20 +0100 |
commit | ec90eb99b7d7da3f17177b1b731503d3d4a177b3 (patch) | |
tree | 80512fd17112fcdb38c69c303023bbb49257bd37 | |
parent | f5536c6121077ea5d70d488e40af78acccc5cd8f (diff) | |
download | gitlab-ce-ec90eb99b7d7da3f17177b1b731503d3d4a177b3.tar.gz |
Merge branch 'security-11-4-2717-xss-username-autocomplete' into 'security-11-4'
[11.4] Escape user fullname while rendering autocomplete template to prevent XSS
See merge request gitlab/gitlabhq!2607
-rw-r--r-- | app/assets/javascripts/gfm_auto_complete.js | 15 | ||||
-rw-r--r-- | changelogs/unreleased/security-11-4-2717-xss-username-autocomplete.yml | 5 | ||||
-rw-r--r-- | spec/features/issues/gfm_autocomplete_spec.rb | 31 |
3 files changed, 40 insertions, 11 deletions
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js index 7dd0efd622d..337a70a270a 100644 --- a/app/assets/javascripts/gfm_auto_complete.js +++ b/app/assets/javascripts/gfm_auto_complete.js @@ -151,10 +151,16 @@ class GfmAutoComplete { // Team Members $input.atwho({ at: '@', + alias: 'users', displayTpl(value) { let tmpl = GfmAutoComplete.Loading.template; - if (value.username != null) { - tmpl = GfmAutoComplete.Members.template; + const { avatarTag, username, title } = value; + if (username != null) { + tmpl = GfmAutoComplete.Members.templateFunction({ + avatarTag, + username, + title, + }); } return tmpl; }, @@ -548,8 +554,9 @@ GfmAutoComplete.Emoji = { }; // Team Members GfmAutoComplete.Members = { - // eslint-disable-next-line no-template-curly-in-string - template: '<li>${avatarTag} ${username} <small>${title}</small></li>', + templateFunction({ avatarTag, username, title }) { + return `<li>${avatarTag} ${username} <small>${_.escape(title)}</small></li>`; + }, }; GfmAutoComplete.Labels = { // eslint-disable-next-line no-template-curly-in-string diff --git a/changelogs/unreleased/security-11-4-2717-xss-username-autocomplete.yml b/changelogs/unreleased/security-11-4-2717-xss-username-autocomplete.yml new file mode 100644 index 00000000000..d9b1015eeb4 --- /dev/null +++ b/changelogs/unreleased/security-11-4-2717-xss-username-autocomplete.yml @@ -0,0 +1,5 @@ +--- +title: Escape user fullname while rendering autocomplete template to prevent XSS +merge_request: +author: +type: security diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 593dc6b6690..7c591dacce5 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -1,6 +1,10 @@ require 'rails_helper' describe 'GFM autocomplete', :js do + let(:issue_xss_title) { 'This will execute alert<img src=x onerror=alert(2)<img src=x onerror=alert(1)>' } + let(:user_xss_title) { 'eve <img src=x onerror=alert(2)<img src=x onerror=alert(1)>' } + + let(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') } let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') } let(:project) { create(:project) } let(:label) { create(:label, project: project, title: 'special+') } @@ -9,13 +13,15 @@ describe 'GFM autocomplete', :js do before do project.add_maintainer(user) + project.add_maintainer(user_xss) + sign_in(user) visit project_issue_path(project, issue) wait_for_requests end - it 'updates issue descripton with GFM reference' do + it 'updates issue description with GFM reference' do find('.js-issuable-edit').click simulate_input('#issue-description', "@#{user.name[0...3]}") @@ -35,9 +41,8 @@ describe 'GFM autocomplete', :js do expect(page).to have_selector('.atwho-container') end - it 'opens autocomplete menu when field starts with text with item escaping HTML characters' do - alert_title = 'This will execute alert<img src=x onerror=alert(2)<img src=x onerror=alert(1)>' - create(:issue, project: project, title: alert_title) + it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do + create(:issue, project: project, title: issue_xss_title) page.within '.timeline-content-form' do find('#note-body').native.send_keys('#') @@ -46,7 +51,19 @@ describe 'GFM autocomplete', :js do expect(page).to have_selector('.atwho-container') page.within '.atwho-container #at-view-issues' do - expect(page.all('li').first.text).to include(alert_title) + expect(page.all('li').first.text).to include(issue_xss_title) + end + end + + it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do + page.within '.timeline-content-form' do + find('#note-body').native.send_keys('@ev') + end + + expect(page).to have_selector('.atwho-container') + + page.within '.atwho-container #at-view-users' do + expect(find('li').text).to have_content(user_xss.username) end end @@ -107,7 +124,7 @@ describe 'GFM autocomplete', :js do wait_for_requests - expect(find('#at-view-64')).to have_selector('.cur:first-of-type') + expect(find('#at-view-users')).to have_selector('.cur:first-of-type') end it 'includes items for assignee dropdowns with non-ASCII characters in name' do @@ -120,7 +137,7 @@ describe 'GFM autocomplete', :js do wait_for_requests - expect(find('#at-view-64')).to have_content(user.name) + expect(find('#at-view-users')).to have_content(user.name) end it 'selects the first item for non-assignee dropdowns if a query is entered' do |