Skip to content

Commit d84e9c3

Browse files
committedJul 6, 2021
dummyAnchor href check
1 parent bae378a commit d84e9c3

File tree

2 files changed

+45
-12
lines changed

2 files changed

+45
-12
lines changed
 

‎src/lib/svg_text_utils.js

+27-12
Original file line numberDiff line numberDiff line change
@@ -604,14 +604,9 @@ function buildSVGText(containerNode, str) {
604604
var href = getQuotedMatch(extra, HREFMATCH);
605605

606606
if(href) {
607-
// check safe protocols
608-
var dummyAnchor = document.createElement('a');
609-
dummyAnchor.href = href;
610-
if(PROTOCOLS.indexOf(dummyAnchor.protocol) !== -1) {
611-
// Decode href to allow both already encoded and not encoded
612-
// URIs. Without decoding prior encoding, an already encoded
613-
// URI would be encoded twice producing a semantically different URI.
614-
nodeSpec.href = encodeURI(decodeURI(href));
607+
var safeHref = sanitizeHref(href);
608+
if(safeHref) {
609+
nodeSpec.href = safeHref;
615610
nodeSpec.target = getQuotedMatch(extra, TARGETMATCH) || '_blank';
616611
nodeSpec.popup = getQuotedMatch(extra, POPUPMATCH);
617612
}
@@ -626,6 +621,27 @@ function buildSVGText(containerNode, str) {
626621
return hasLink;
627622
}
628623

624+
function sanitizeHref(href) {
625+
var decodedHref = encodeURI(decodeURI(href));
626+
var dummyAnchor1 = document.createElement('a');
627+
var dummyAnchor2 = document.createElement('a');
628+
dummyAnchor1.href = href;
629+
dummyAnchor2.href = decodedHref;
630+
631+
var p1 = dummyAnchor1.protocol;
632+
var p2 = dummyAnchor2.protocol;
633+
634+
// check safe protocols
635+
if(
636+
PROTOCOLS.indexOf(p1) !== -1 &&
637+
PROTOCOLS.indexOf(p2) !== -1
638+
) {
639+
return decodedHref;
640+
} else {
641+
return '';
642+
}
643+
}
644+
629645
/*
630646
* sanitizeHTML: port of buildSVGText aimed at providing a clean subset of HTML
631647
* @param {string} str: the html string to clean
@@ -660,10 +676,9 @@ exports.sanitizeHTML = function sanitizeHTML(str) {
660676
var href = getQuotedMatch(extra, HREFMATCH);
661677

662678
if(href) {
663-
var dummyAnchor = document.createElement('a');
664-
dummyAnchor.href = href;
665-
if(PROTOCOLS.indexOf(dummyAnchor.protocol) !== -1) {
666-
nodeAttrs.href = encodeURI(decodeURI(href));
679+
var safeHref = sanitizeHref(href);
680+
if(safeHref) {
681+
nodeAttrs.href = safeHref;
667682
var target = getQuotedMatch(extra, TARGETMATCH);
668683
if(target) {
669684
nodeAttrs.target = target;

‎test/jasmine/tests/svg_text_utils_test.js

+18
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ describe('svg+text utils', function() {
8585
d3.selectAll('.text-tester').remove();
8686
});
8787

88+
it('checks for XSS attack in href protocol', function() {
89+
var node = mockTextSVGElement(
90+
'<a href="j%61vascript:alert(\'attack\')">XSS</a>'
91+
);
92+
93+
expect(node.text()).toEqual('XSS');
94+
assertAnchorAttrs(node);
95+
assertAnchorLink(node, null);
96+
});
97+
8898
it('checks for XSS attack in href', function() {
8999
var node = mockTextSVGElement(
90100
'<a href="javascript:alert(\'attack\')">XSS</a>'
@@ -534,6 +544,14 @@ describe('sanitizeHTML', function() {
534544
d3.selectAll('.text-tester').remove();
535545
});
536546

547+
it('checks for XSS attack in href protocol', function() {
548+
var innerHTML = mockHTML(
549+
'<a href="j%61vascript:alert(\'attack\')">XSS</a>'
550+
);
551+
552+
expect(innerHTML).toEqual('<a>XSS</a>');
553+
});
554+
537555
it('checks for XSS attack in href', function() {
538556
var innerHTML = mockHTML(
539557
'<a href="javascript:alert(\'attack\')">XSS</a>'

0 commit comments

Comments
 (0)
Please sign in to comment.