CVE-2018-20801 (JavaScript, published 2019-03-14T16:29Z)
Description: value: In js/parts/SvgRenderer.js in Highcharts JS before 6.1.0, the use of backtracking regular expressions permitted an attacker to conduct a denial of service attack against the SVGRenderer component, aka ReDoS.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-185 \u2014 Incorrect Regular Expression
The product specifies a regular expression in a way that causes data to be improperly matched or compared.
Repository: https://github.com/highcharts/highcharts
Files changed:
js/parts/SvgRenderer.js
package.json
samples/unit-tests/svgrenderer/text/demo.js
Commit message: Refactored SVGRenderer text to not use backtracking regexes to replace attributes.

Adds support for single quoted class, href and style attributes in strings.


Vulnerable code:
			clsRegex,
			styleRegex,
			hrefRegex,
			clsRegex = /<.*class="([^"]+)".*>/;
			styleRegex = /<.*style="([^"]+)".*>/;
			hrefRegex = /<.*href="([^"]+)".*>/;

							spanCls,
							spanStyle; // #390
						if (clsRegex.test(span)) {
							spanCls = span.match(clsRegex)[1];
							attr(tspan, 'class', spanCls);
						if (styleRegex.test(span)) {
							spanStyle = span.match(styleRegex)[1].replace(
							attr(tspan, 'style', spanStyle);
						if (hrefRegex.test(span) && !forExport) {
								'location.href=\"' +
									span.match(hrefRegex)[1] + '\"'
											if (spanStyle) { // #390
												attr(tspan, 'style', spanStyle);

Fixed code:
			},
			parseAttribute = function (s, attr) {
				var start,
					delimiter;

				start = s.indexOf('<');
				s = s.substring(start, s.indexOf('>') - start);

				start = s.indexOf(attr + '=');
				if (start !== -1) {
					start = start + attr.length + 1;
					delimiter = s.charAt(start);
					if (delimiter === '"' || delimiter === "'") { // eslint-disable-line quotes
						s = s.substring(start + 1);
						return s.substring(0, s.indexOf(delimiter));
					}
				}
							classAttribute,
							styleAttribute, // #390
							hrefAttribute;
						
						classAttribute = parseAttribute(span, 'class');
						if (classAttribute) {
							attr(tspan, 'class', classAttribute);

						styleAttribute = parseAttribute(span, 'style');
						if (styleAttribute) {
							styleAttribute = styleAttribute.replace(
							attr(tspan, 'style', styleAttribute);
						hrefAttribute = parseAttribute(span, 'href');
						if (hrefAttribute && !forExport) {
								'location.href=\"' + hrefAttribute + '\"'
											if (styleAttribute) { // #390
												attr(
													tspan,
													'style',
													styleAttribute
												);
    "safe-regex": "^1.1.0",

QUnit.test('Attributes', function (assert) {
    var ren = new Highcharts.Renderer(
        document.getElementById('container'),
        600,
        400
    );

    var text = ren
        .text(
            'The quick brown fox jumps <span class="red">over</span> the lazy dog',
            20,
            20
        )
        .add();

    assert.strictEqual(
        text.element.childNodes[1].getAttribute('class'),
        'red',
        'Double quotes, red span should be picked up'
    );

    text = ren
        .text(
            "The quick brown fox jumps <span class='red'>over</span> the lazy dog",
            20,
            20
        )
        .add();

    assert.strictEqual(
        text.element.childNodes[1].getAttribute('class'),
        'red',
        'Single quotes, red span should be picked up'
    );
});