CVE-2016-7103: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site scripting (XSS) vulnerability in jQuery UI before 1.12.0 might allow remote attackers to inject arbitrary web script or HTML via the closeText parameter of the dialog function.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2017-03-15T16:59Z
Repository: https://github.com/jquery/jquery-ui
Language: JavaScript
Files changed: tests/unit/dialog/options.js, ui/widgets/dialog.js
Commit date: 2015-10-28 19:48:35 +0100
Commit message: Dialog: Escape closeText option before passing it to button

Ref gh-1632
Fixes jquery/api.jqueryui.com#281

Diff: diff --git a/tests/unit/dialog/options.js b/tests/unit/dialog/options.js
index 6d3a619bd..ab9ace259 100644
--- a/tests/unit/dialog/options.js
+++ b/tests/unit/dialog/options.js
@@ -204,11 +204,11 @@ test( "closeOnEscape", function() {
 		.simulate( "keyup", { keyCode: $.ui.keyCode.ESCAPE } );
 	ok( element.dialog( "widget" ).is( ":hidden" ) && !element.dialog( "widget" ).is( ":visible" ), "dialog is closed after ESC" );
 } );
 
 test( "closeText", function() {
-	expect( 3 );
+	expect( 4 );
 
 	var element = $( "<div></div>" ).dialog();
 		equal( $.trim( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "Close",
 			"default close text" );
 	element.remove();
@@ -220,10 +220,15 @@ test( "closeText", function() {
 
 	element = $( "<div></div>" ).dialog().dialog( "option", "closeText", "bar" );
 		equal( $.trim( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "bar",
 			"closeText via option method" );
 	element.remove();
+
+	element = $( "<div></div>" ).dialog( { closeText: "<span>foo</span>" } );
+		equal( $.trim( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "<span>foo</span>",
+			"closeText is escaped" );
+	element.remove();
 } );
 
 test( "draggable", function() {
 	expect( 4 );
 
diff --git a/ui/widgets/dialog.js b/ui/widgets/dialog.js
index f0a2f6751..c3ca95ed3 100644
--- a/ui/widgets/dialog.js
+++ b/ui/widgets/dialog.js
@@ -424,11 +424,11 @@ $.widget( "ui.dialog", {
 		// Support: IE
 		// Use type="button" to prevent enter keypresses in textboxes from closing the
 		// dialog in IE (#9312)
 		this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
 			.button( {
-				label: this.options.closeText,
+				label: $( "<a>" ).text( this.options.closeText ).html(),
 				icon: "ui-icon-closethick",
 				showLabel: false
 			} )
 			.appendTo( this.uiDialogTitlebar );
 
@@ -713,11 +713,11 @@ $.widget( "ui.dialog", {
 
 		if ( key === "closeText" ) {
 			this.uiDialogTitlebarClose.button( {
 
 				// Ensure that we always pass a string
-				label: "" + value
+				label: $( "<a>" ).text( "" + this.options.closeText ).html()
 			} );
 		}
 
 		if ( key === "draggable" ) {
 			isDraggable = uiDialog.is( ":data(ui-draggable)" );

Vulnerable code: 	expect( 3 );
				label: this.options.closeText,
				label: "" + value
Fixed code: 	expect( 4 );

	element = $( "<div></div>" ).dialog( { closeText: "<span>foo</span>" } );
		equal( $.trim( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "<span>foo</span>",
			"closeText is escaped" );
	element.remove();
				label: $( "<a>" ).text( this.options.closeText ).html(),
				label: $( "<a>" ).text( "" + this.options.closeText ).html()