Changeset - 429c2c8a4354
[Not reviewed]
default
0 1 0
Mads Kiilerich - 7 years ago 2019-02-27 02:23:26
mads@kiilerich.com
pullrequests: prevent XSS in @mention completion when first and last names cannot be trusted

atwho used in MentionsAutoComplete is passing raw user controlled data which
might contain HTML markup.

That could cause XSS issues when completion hit a rogue user name.

To avoid that, make sure displayTpl always escape user information, as
recommended in https://github.com/ichord/At.js/issues/334 .
1 file changed with 7 insertions and 1 deletions:
0 comments (0 inline, 0 general)
kallithea/public/js/base.js
Show inline comments
 
@@ -1153,97 +1153,103 @@ var SimpleUserAutoComplete = function ($
 
var MembersAutoComplete = function ($inputElement, $typeElement) {
 

	
 
    $inputElement.select2({
 
        placeholder: $inputElement.attr('placeholder'),
 
        minimumInputLength: 1,
 
        ajax: {
 
            url: pyroutes.url('users_and_groups_data'),
 
            dataType: 'json',
 
            data: function(term, page){
 
              return {
 
                query: term,
 
                types: 'users,groups'
 
              };
 
            },
 
            results: function (data, page){
 
              return data;
 
            },
 
            cache: true
 
        },
 
        formatSelection: autocompleteFormatter,
 
        formatResult: autocompleteFormatter,
 
        id: function(item) { return item.type == 'user' ? item.nname : item.grname },
 
    }).on("select2-selecting", function(e) {
 
        // e.choice.id is automatically used as selection value - just set the type of the selection
 
        $typeElement.val(e.choice.type);
 
    });
 
}
 

	
 
var MentionsAutoComplete = function ($inputElement) {
 
  $inputElement.atwho({
 
    at: "@",
 
    callbacks: {
 
      remoteFilter: function(query, callback) {
 
        $.getJSON(
 
          pyroutes.url('users_and_groups_data'),
 
          {
 
            query: query,
 
            types: 'users'
 
          },
 
          function(data) {
 
            callback(data.results)
 
          }
 
        );
 
      },
 
      sorter: function(query, items, searchKey) {
 
        return items;
 
      }
 
    },
 
    displayTpl: "<li>" + autocompleteGravatar('${fname} ${lname} (${nname})', '${gravatar_lnk}', 16) + "</li>",
 
    displayTpl: function(item) {
 
        return "<li>" +
 
            autocompleteGravatar(
 
                "{0} {1} ({2})".format(item.fname, item.lname, item.nname).html_escape(),
 
                '${gravatar_lnk}', 16) +
 
            "</li>";
 
    },
 
    insertTpl: "${atwho-at}${nname}"
 
  });
 
};
 

	
 

	
 
// Set caret at the given position in the input element
 
function _setCaretPosition($inputElement, caretPos) {
 
    $inputElement.each(function(){
 
        if(this.createTextRange) { // IE
 
            var range = this.createTextRange();
 
            range.move('character', caretPos);
 
            range.select();
 
        }
 
        else if(this.selectionStart) { // other recent browsers
 
            this.focus();
 
            this.setSelectionRange(caretPos, caretPos);
 
        }
 
        else // last resort - very old browser
 
            this.focus();
 
    });
 
}
 

	
 

	
 
var addReviewMember = function(id,fname,lname,nname,gravatar_link,gravatar_size){
 
    var displayname = nname;
 
    if ((fname != "") && (lname != "")) {
 
        displayname = "{0} {1} ({2})".format(fname, lname, nname);
 
    }
 
    var gravatarelm = gravatar(gravatar_link, gravatar_size, "");
 
    // WARNING: the HTML below is duplicate with
 
    // kallithea/templates/pullrequests/pullrequest_show.html
 
    // If you change something here it should be reflected in the template too.
 
    var element = (
 
        '     <li id="reviewer_{2}">\n'+
 
        '       <span class="reviewers_member">\n'+
 
        '         <input type="hidden" value="{2}" name="review_members" />\n'+
 
        '         <span class="reviewer_status" data-toggle="tooltip" title="not_reviewed">\n'+
 
        '             <i class="icon-circle changeset-status-not_reviewed"></i>\n'+
 
        '         </span>\n'+
 
        (gravatarelm ?
 
        '         {0}\n' :
 
        '')+
 
        '         <span>{1}</span>\n'+
 
        '         <a href="#" class="reviewer_member_remove" onclick="removeReviewMember({2})">\n'+
 
        '             <i class="icon-minus-circled"></i>\n'+
 
        '         </a> (add not saved)\n'+
 
        '       </span>\n'+
 
        '     </li>\n'
0 comments (0 inline, 0 general)