summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Azzopardi <sazzopardi@gitlab.com>2018-11-18 10:33:22 +0000
committerSteve Azzopardi <steveazz@outlook.com>2018-11-18 11:47:57 +0100
commit953f789fd3dd9bcb1f2f20410c116557187df231 (patch)
tree33eda54807b7d0824cb27ca20045e431247b9eff
parente70f2a5b944653e6fa1f155e79b2c1dab83cb650 (diff)
downloadgitlab-ce-953f789fd3dd9bcb1f2f20410c116557187df231.tar.gz
Merge branch 'security-11-3-2717-xss-username-autocomplete' into 'security-11-3'
[11.3] Escape user fullname while rendering autocomplete template to prevent XSS See merge request gitlab/gitlabhq!2608
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js15
-rw-r--r--changelogs/unreleased/security-11-3-2717-xss-username-autocomplete.yml5
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb29
3 files changed, 39 insertions, 10 deletions
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 03256ca2285..a0454354fd0 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -149,10 +149,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;
},
@@ -512,8 +518,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-3-2717-xss-username-autocomplete.yml b/changelogs/unreleased/security-11-3-2717-xss-username-autocomplete.yml
new file mode 100644
index 00000000000..d9b1015eeb4
--- /dev/null
+++ b/changelogs/unreleased/security-11-3-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 8a43847d64d..6a275a78d28 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)&lt;img src=x onerror=alert(1)&gt;' }
+ let(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
+
+ 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+') }
@@ -8,6 +12,8 @@ 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)
@@ -34,9 +40,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)&lt;img src=x onerror=alert(1)&gt;'
- 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('#')
@@ -45,7 +50,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
@@ -106,7 +123,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
@@ -119,7 +136,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