Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit a5a860e

Browse files
committed
fix(select): block xss on md-select-label
1 parent 088d2e6 commit a5a860e

File tree

2 files changed

+47
-7
lines changed

2 files changed

+47
-7
lines changed

src/components/select/select.js

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ angular.module('material.components.select', [
174174
* </div>
175175
* </hljs>
176176
*/
177-
function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $parse) {
177+
function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $parse, $sce,
178+
$injector) {
178179
var keyCodes = $mdConstant.KEY_CODE;
179180
var NAVIGATION_KEYS = [keyCodes.SPACE, keyCodes.ENTER, keyCodes.UP_ARROW, keyCodes.DOWN_ARROW];
180181

@@ -337,17 +338,41 @@ function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $
337338
mdSelectCtrl.setLabelText = function(text) {
338339
mdSelectCtrl.setIsPlaceholder(!text);
339340

340-
if (attr.mdSelectedText) {
341-
text = $parse(attr.mdSelectedText)(scope);
342-
} else {
341+
// Whether the select label has been given via user content rather than the internal
342+
// template of <md-option>
343+
var isSelectLabelFromUser = false;
344+
345+
if (attr.mdSelectedText && attr.mdSelectedHtml) {
346+
throw Error('md-select cannot have both `md-selected-text` and `md-selected-html`');
347+
}
348+
349+
if (attr.mdSelectedText || attr.mdSelectedHtml) {
350+
text = $parse(attr.mdSelectedText || attr.mdSelectedHtml)(scope);
351+
isSelectLabelFromUser = true;
352+
} else if (!text) {
343353
// Use placeholder attribute, otherwise fallback to the md-input-container label
344354
var tmpPlaceholder = attr.placeholder ||
345355
(containerCtrl && containerCtrl.label ? containerCtrl.label.text() : '');
346-
text = text || tmpPlaceholder || '';
356+
357+
text = tmpPlaceholder || '';
358+
isSelectLabelFromUser = true;
347359
}
348360

349361
var target = valueEl.children().eq(0);
350-
target.html(text);
362+
363+
if (attr.mdSelectedHtml) {
364+
if (!$injector.has('$sanitize')) {
365+
throw Error('The ngSanitize module must be loaded in order to use ' +
366+
'md-treat-selected-text-as-html.');
367+
}
368+
369+
target.html($sce.getTrustedHtml(text));
370+
} else if (isSelectLabelFromUser) {
371+
target.text(text);
372+
} else {
373+
// If we've reached this point, the text is not user-provided.
374+
target.html(text);
375+
}
351376
};
352377

353378
mdSelectCtrl.setIsPlaceholder = function(isPlaceholder) {

src/components/select/select.spec.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ describe('<md-select>', function() {
33
var body, $document, $rootScope, $compile, $timeout, $material;
44

55
beforeEach(function() {
6-
module('material.components.select', 'material.components.input');
6+
module('material.components.select', 'material.components.input', 'ngSanitize');
77

88
inject(function($injector) {
99
$document = $injector.get('$document');
@@ -437,6 +437,21 @@ describe('<md-select>', function() {
437437
expect(label.text()).toBe($rootScope.selectedText);
438438
});
439439

440+
it('should sanitize md-selected-text', function() {
441+
$rootScope.selectedText = '<b>Hello World</b><script>window.mdSelectXss="YES"</script>';
442+
443+
var select = setupSelect(
444+
'ng-model="someVal", ' +
445+
'md-selected-html="selectedText"', null, true).find('md-select');
446+
var label = select.find('md-select-value');
447+
448+
expect(label.text()).toBe('Hello World');
449+
450+
// The label is loaded into a span that is the first child of the '<md-select-value>`.
451+
expect(label[0].childNodes[0].innerHTML).toBe('<b>Hello World</b>');
452+
expect(window.mdSelectXss).toBeUndefined();
453+
});
454+
440455
it('supports rendering multiple', function() {
441456
$rootScope.val = [1, 3];
442457
var select = $compile('<md-input-container>' +

0 commit comments

Comments
 (0)