@@ -1841,12 +1841,11 @@ impl<'a> Builder<'a> {
18411841 let parent = node. parent
18421842 . replace ( None ) . expect ( "a node in the DOM will have a parent, except the root, which is not processed" )
18431843 . upgrade ( ) . expect ( "a node's parent will be pointed to by its parent (or the root pointer), and will not be dropped" ) ;
1844- if self . clean_node_content ( & node) {
1844+ if self . clean_node_content ( & node) || ! self . check_expected_namespace ( & parent , & node ) {
18451845 removed. push ( node) ;
18461846 continue ;
18471847 }
1848- let pass_clean = self . clean_child ( & mut node) ;
1849- let pass = pass_clean && self . check_expected_namespace ( & parent, & node) ;
1848+ let pass = self . clean_child ( & mut node) ;
18501849 if pass {
18511850 self . adjust_node_attributes ( & mut node, & link_rel, self . id_prefix ) ;
18521851 dom. append ( & parent. clone ( ) , NodeOrText :: AppendNode ( node. clone ( ) ) ) ;
@@ -2053,21 +2052,18 @@ impl<'a> Builder<'a> {
20532052 matches ! (
20542053 & * parent. local,
20552054 "mi" | "mo" | "mn" | "ms" | "mtext" | "annotation-xml"
2056- )
2055+ ) && if child . ns == ns ! ( html ) { is_html_tag ( & child . local ) } else { true }
20572056 // The only way to switch from svg to mathml/html is with an html integration point
20582057 } else if parent. ns == ns ! ( svg) && child. ns != ns ! ( svg) {
20592058 // https://html.spec.whatwg.org/#svg-0
20602059 matches ! ( & * parent. local, "foreignObject" )
2060+ && if child. ns == ns ! ( html) { is_html_tag ( & child. local ) } else { true }
20612061 } else if child. ns == ns ! ( svg) {
20622062 is_svg_tag ( & child. local )
20632063 } else if child. ns == ns ! ( mathml) {
20642064 is_mathml_tag ( & child. local )
20652065 } else if child. ns == ns ! ( html) {
2066- ( !is_svg_tag ( & child. local ) && !is_mathml_tag ( & child. local ) )
2067- || matches ! (
2068- & * child. local,
2069- "title" | "style" | "font" | "a" | "script" | "span"
2070- )
2066+ is_html_tag ( & child. local )
20712067 } else {
20722068 // There are no other supported ways to switch namespace
20732069 parent. ns == child. ns
@@ -2224,6 +2220,14 @@ fn is_url_attr(element: &str, attr: &str) -> bool {
22242220 || ( element == "video" && attr == "poster" )
22252221}
22262222
2223+ fn is_html_tag ( element : & str ) -> bool {
2224+ ( !is_svg_tag ( element) && !is_mathml_tag ( element) )
2225+ || matches ! (
2226+ element,
2227+ "title" | "style" | "font" | "a" | "script" | "span"
2228+ )
2229+ }
2230+
22272231/// Given an element name, check if it's SVG
22282232fn is_svg_tag ( element : & str ) -> bool {
22292233 // https://svgwg.org/svg2-draft/eltindex.html
@@ -3630,15 +3634,15 @@ mod test {
36303634 // https://github.com/cure53/DOMPurify/pull/495
36313635 let fragment = r##"<svg><iframe><a title="</iframe><img src onerror=alert(1)>">test"## ;
36323636 let result = String :: from ( Builder :: new ( ) . add_tags ( & [ "iframe" ] ) . clean ( fragment) ) ;
3633- assert_eq ! ( result. to_string( ) , "test " ) ;
3637+ assert_eq ! ( result. to_string( ) , "" ) ;
36343638
36353639 let fragment = "<svg><iframe>remove me</iframe></svg><iframe>keep me</iframe>" ;
36363640 let result = String :: from ( Builder :: new ( ) . add_tags ( & [ "iframe" ] ) . clean ( fragment) ) ;
3637- assert_eq ! ( result. to_string( ) , "remove me <iframe>keep me</iframe>" ) ;
3641+ assert_eq ! ( result. to_string( ) , "<iframe>keep me</iframe>" ) ;
36383642
36393643 let fragment = "<svg><a>remove me</a></svg><iframe>keep me</iframe>" ;
36403644 let result = String :: from ( Builder :: new ( ) . add_tags ( & [ "iframe" ] ) . clean ( fragment) ) ;
3641- assert_eq ! ( result. to_string( ) , "remove me <iframe>keep me</iframe>" ) ;
3645+ assert_eq ! ( result. to_string( ) , "<iframe>keep me</iframe>" ) ;
36423646
36433647 let fragment = "<svg><a>keep me</a></svg><iframe>keep me</iframe>" ;
36443648 let result = String :: from ( Builder :: new ( ) . add_tags ( & [ "iframe" , "svg" ] ) . clean ( fragment) ) ;
@@ -3648,6 +3652,19 @@ mod test {
36483652 ) ;
36493653 }
36503654
3655+ #[ test]
3656+ fn ns_svg_2 ( ) {
3657+ let fragment = "<svg><foreignObject><table><path><xmp><!--</xmp><img title'--><img src=1 onerror=alert(1)>'>" ;
3658+ let result = Builder :: default ( )
3659+ . strip_comments ( false )
3660+ . add_tags ( & [ "svg" , "foreignObject" , "table" , "path" , "xmp" ] )
3661+ . clean ( fragment) ;
3662+ assert_eq ! (
3663+ result. to_string( ) ,
3664+ "<svg><foreignObject><table></table></foreignObject></svg>"
3665+ ) ;
3666+ }
3667+
36513668 #[ test]
36523669 fn ns_mathml ( ) {
36533670 // https://github.com/cure53/DOMPurify/pull/495
@@ -3680,6 +3697,20 @@ mod test {
36803697 ) ;
36813698 }
36823699
3700+ #[ test]
3701+ fn ns_mathml_2 ( ) {
3702+ let fragment = "<math><mtext><table><mglyph><xmp><!--</xmp><img title='--><img src=1 onerror=alert(1)>'>" ;
3703+ let result = Builder :: default ( )
3704+ . strip_comments ( false )
3705+ . add_tags ( & [ "math" , "mtext" , "table" , "mglyph" , "xmp" ] )
3706+ . clean ( fragment) ;
3707+ assert_eq ! (
3708+ result. to_string( ) ,
3709+ "<math><mtext><table></table></mtext></math>"
3710+ ) ;
3711+ }
3712+
3713+
36833714 #[ test]
36843715 fn xml_processing_instruction ( ) {
36853716 // https://blog.slonser.info/posts/dompurify-node-type-confusion/
0 commit comments