diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e4b479..bf33c7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## UNRELEASED +- Added `allowedEmptyAttributes` option and kept empty `alt` value by default. + ## 2.11.0 (2023-06-21) - Fix to allow `false` in `allowedClasses` attributes. Thanks to [Kevin Jiang](https://github.com/KevinSJ) for this fix! diff --git a/index.js b/index.js index b834977..4ea238a 100644 --- a/index.js +++ b/index.js @@ -295,9 +295,11 @@ function sanitizeHtml(html, options, _recursing) { delete frame.attribs[a]; return; } - // If the value is empty, and this is a known non-boolean attribute, delete it + // If the value is empty, check if the attribute is in the allowedEmptyAttributes array. + // If it is not in the allowedEmptyAttributes array, and it is a known non-boolean attribute, delete it // List taken from https://html.spec.whatwg.org/multipage/indices.html#attributes-3 - if (value === '' && (options.nonBooleanAttributes.includes(a) || options.nonBooleanAttributes.includes('*'))) { + if (value === '' && (!options.allowedEmptyAttributes.includes(a)) && (options.nonBooleanAttributes.includes(a) || + options.nonBooleanAttributes.includes('*'))) { delete frame.attribs[a]; return; } @@ -474,6 +476,8 @@ function sanitizeHtml(html, options, _recursing) { result += ' ' + a; if (value && value.length) { result += '="' + escapeHtml(value, true) + '"'; + } else if (options.allowedEmptyAttributes.includes(a)) { + result += '=""'; } } else { delete frame.attribs[a]; @@ -876,6 +880,9 @@ sanitizeHtml.defaults = { // these attributes would make sense if we did. img: [ 'src', 'srcset', 'alt', 'title', 'width', 'height', 'loading' ] }, + allowedEmptyAttributes: [ + 'alt' + ], // Lots of these won't come up by default because we don't allow them selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ], // URL schemes we permit diff --git a/test/test.js b/test/test.js index c938b33..0ce92a2 100644 --- a/test/test.js +++ b/test/test.js @@ -1616,4 +1616,27 @@ describe('sanitizeHtml', function() { nonBooleanAttributes: [ '*' ] }), ''); }); + it('should not remove empty alt attribute value by default', function() { + assert.equal(sanitizeHtml('', { + allowedAttributes: { img: [ 'alt', 'src' ] }, + allowedTags: [ 'img' ] + }), ''); + }); + it('should not remove empty alt attribute value by default when disabled', function() { + assert.equal(sanitizeHtml('', { + allowedAttributes: { img: [ 'alt', 'src' ] }, + allowedTags: [ 'img' ], + nonBooleanAttributes: [] + }), ''); + }); + it('should set empty value to attribute specified in allowedEmptyAttributes option', function() { + assert.equal(sanitizeHtml('hello', { + allowedEmptyAttributes: [ 'href' ] + }), 'hello'); + }); + it('should not remove empty attribute specified in allowedEmptyAttributes option', function() { + assert.equal(sanitizeHtml('hello', { + allowedEmptyAttributes: [ 'href' ] + }), 'hello'); + }); });