From 1538ebe9c2d8b9aec84d1f556a9b4cfe5a38dc04 Mon Sep 17 00:00:00 2001 From: Robert Messerle Date: Tue, 19 May 2015 19:14:28 -0700 Subject: [PATCH] fix(autocomplete): resolves xss bug with autocomplete text highlighter Closes #2901 --- .../autocomplete/autocomplete.spec.js | 41 +++++++++++++++++-- .../autocomplete/js/highlightController.js | 3 +- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/components/autocomplete/autocomplete.spec.js b/src/components/autocomplete/autocomplete.spec.js index 84afc9f1080..29014989af5 100644 --- a/src/components/autocomplete/autocomplete.spec.js +++ b/src/components/autocomplete/autocomplete.spec.js @@ -11,9 +11,9 @@ describe('', function() { return container; } - function createScope () { + function createScope (items) { var scope; - var items = ['foo', 'bar', 'baz'].map(function (item) { return { display: item }; }); + items = items || ['foo', 'bar', 'baz'].map(function (item) { return { display: item }; }); inject(function ($rootScope) { scope = $rootScope.$new(); scope.match = function (term) { @@ -28,7 +28,7 @@ describe('', function() { } describe('basic functionality', function () { - it('should fail', inject(function($timeout, $mdConstant, $rootElement) { + it('should support basic functionality', inject(function($timeout, $mdConstant, $rootElement) { var scope = createScope(); var template = '\ ', function() { })); }); + describe('xss prevention', function () { + it('should not allow html to slip through', inject(function($timeout, $mdConstant, $rootElement) { + var html = 'foo '; + var scope = createScope([ { display: html } ]); + var template = '\ + \ + {{item.display}}\ + '; + var element = compile(template, scope); + var ctrl = element.controller('mdAutocomplete'); + var ul = element.find('ul'); + + expect(scope.searchText).toBe(''); + expect(scope.selectedItem).toBe(null); + + element.scope().searchText = 'fo'; + ctrl.keydown({}); + element.scope().$apply(); + $timeout.flush(); + + expect(scope.searchText).toBe('fo'); + expect(scope.match(scope.searchText).length).toBe(1); + expect(ul.find('li').length).toBe(1); + expect(ul.find('li').find('img').length).toBe(0); + + scope.$apply(); + })); + }); + describe('API access', function() { it('should clear the selected item', inject(function($timeout, $mdConstant) { var scope = createScope(); diff --git a/src/components/autocomplete/js/highlightController.js b/src/components/autocomplete/js/highlightController.js index 385109ef292..fd8d9d4c6e2 100644 --- a/src/components/autocomplete/js/highlightController.js +++ b/src/components/autocomplete/js/highlightController.js @@ -4,7 +4,8 @@ angular function MdHighlightCtrl ($scope, $element, $interpolate) { var term = $element.attr('md-highlight-text'), - text = $interpolate($element.html())($scope), + unsafeText = $interpolate($element.html())($scope), + text = angular.element('
').text(unsafeText).html(), flags = $element.attr('md-highlight-flags') || '', watcher = $scope.$watch(term, function (term) { var regex = getRegExp(term, flags),