@@ -295,9 +295,11 @@ function sanitizeHtml(html, options, _recursing) {
295295 delete frame . attribs [ a ] ;
296296 return ;
297297 }
298- // If the value is empty, and this is a known non-boolean attribute, delete it
298+ // If the value is empty, check if the attribute is in the allowedEmptyAttributes array.
299+ // If it is not in the allowedEmptyAttributes array, and it is a known non-boolean attribute, delete it
299300 // List taken from https://html.spec.whatwg.org/multipage/indices.html#attributes-3
300- if ( value === '' && ( options . nonBooleanAttributes . includes ( a ) || options . nonBooleanAttributes . includes ( '*' ) ) ) {
301+ if ( value === '' && ( ! options . allowedEmptyAttributes . includes ( a ) ) && ( options . nonBooleanAttributes . includes ( a ) ||
302+ options . nonBooleanAttributes . includes ( '*' ) ) ) {
301303 delete frame . attribs [ a ] ;
302304 return ;
303305 }
@@ -474,6 +476,8 @@ function sanitizeHtml(html, options, _recursing) {
474476 result += ' ' + a ;
475477 if ( value && value . length ) {
476478 result += '="' + escapeHtml ( value , true ) + '"' ;
479+ } else if ( options . allowedEmptyAttributes . includes ( a ) ) {
480+ result += '=""' ;
477481 }
478482 } else {
479483 delete frame . attribs [ a ] ;
@@ -876,6 +880,9 @@ sanitizeHtml.defaults = {
876880 // these attributes would make sense if we did.
877881 img : [ 'src' , 'srcset' , 'alt' , 'title' , 'width' , 'height' , 'loading' ]
878882 } ,
883+ allowedEmptyAttributes : [
884+ 'alt'
885+ ] ,
879886 // Lots of these won't come up by default because we don't allow them
880887 selfClosing : [ 'img' , 'br' , 'hr' , 'area' , 'base' , 'basefont' , 'input' , 'link' , 'meta' ] ,
881888 // URL schemes we permit
0 commit comments