@@ -554,39 +554,174 @@ describe('ReactDOMComponent', () => {
554
554
expect ( stubStyle . color ) . toEqual ( 'green' ) ;
555
555
} ) ;
556
556
557
- it ( 'should reject attribute key injection attack on markup' , ( ) => {
557
+ it ( 'should reject attribute key injection attack on markup for regular DOM (SSR) ' , ( ) => {
558
558
expect ( ( ) => {
559
559
for ( let i = 0 ; i < 3 ; i ++ ) {
560
- const container = document . createElement ( 'div' ) ;
561
- const element = React . createElement (
560
+ const element1 = React . createElement (
561
+ 'div' ,
562
+ { 'blah" onclick="beevil" noise="hi' : 'selected' } ,
563
+ null ,
564
+ ) ;
565
+ const element2 = React . createElement (
566
+ 'div' ,
567
+ { '></div><script>alert("hi")</script>' : 'selected' } ,
568
+ null ,
569
+ ) ;
570
+ let result1 = ReactDOMServer . renderToString ( element1 ) ;
571
+ let result2 = ReactDOMServer . renderToString ( element2 ) ;
572
+ expect ( result1 . toLowerCase ( ) ) . not . toContain ( 'onclick' ) ;
573
+ expect ( result2 . toLowerCase ( ) ) . not . toContain ( 'script' ) ;
574
+ }
575
+ } ) . toWarnDev ( [
576
+ 'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`' ,
577
+ 'Warning: Invalid attribute name: `></div><script>alert("hi")</script>`' ,
578
+ ] ) ;
579
+ } ) ;
580
+
581
+ it ( 'should reject attribute key injection attack on markup for custom elements (SSR)' , ( ) => {
582
+ expect ( ( ) => {
583
+ for ( let i = 0 ; i < 3 ; i ++ ) {
584
+ const element1 = React . createElement (
562
585
'x-foo-component' ,
563
586
{ 'blah" onclick="beevil" noise="hi' : 'selected' } ,
564
587
null ,
565
588
) ;
566
- ReactDOM . render ( element , container ) ;
589
+ const element2 = React . createElement (
590
+ 'x-foo-component' ,
591
+ { '></x-foo-component><script>alert("hi")</script>' : 'selected' } ,
592
+ null ,
593
+ ) ;
594
+ let result1 = ReactDOMServer . renderToString ( element1 ) ;
595
+ let result2 = ReactDOMServer . renderToString ( element2 ) ;
596
+ expect ( result1 . toLowerCase ( ) ) . not . toContain ( 'onclick' ) ;
597
+ expect ( result2 . toLowerCase ( ) ) . not . toContain ( 'script' ) ;
567
598
}
568
- } ) . toWarnDev (
599
+ } ) . toWarnDev ( [
569
600
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`' ,
570
- ) ;
601
+ 'Warning: Invalid attribute name: `></x-foo-component><script>alert("hi")</script>`' ,
602
+ ] ) ;
571
603
} ) ;
572
604
573
- it ( 'should reject attribute key injection attack on update ' , ( ) => {
605
+ it ( 'should reject attribute key injection attack on mount for regular DOM ' , ( ) => {
574
606
expect ( ( ) => {
575
607
for ( let i = 0 ; i < 3 ; i ++ ) {
576
608
const container = document . createElement ( 'div' ) ;
577
- const beforeUpdate = React . createElement ( 'x-foo-component' , { } , null ) ;
609
+ ReactDOM . render (
610
+ React . createElement (
611
+ 'div' ,
612
+ { 'blah" onclick="beevil" noise="hi' : 'selected' } ,
613
+ null ,
614
+ ) ,
615
+ container ,
616
+ ) ;
617
+ expect ( container . firstChild . attributes . length ) . toBe ( 0 ) ;
618
+ ReactDOM . unmountComponentAtNode ( container ) ;
619
+ ReactDOM . render (
620
+ React . createElement (
621
+ 'div' ,
622
+ { '></div><script>alert("hi")</script>' : 'selected' } ,
623
+ null ,
624
+ ) ,
625
+ container ,
626
+ ) ;
627
+ expect ( container . firstChild . attributes . length ) . toBe ( 0 ) ;
628
+ }
629
+ } ) . toWarnDev ( [
630
+ 'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`' ,
631
+ 'Warning: Invalid attribute name: `></div><script>alert("hi")</script>`' ,
632
+ ] ) ;
633
+ } ) ;
634
+
635
+ it ( 'should reject attribute key injection attack on mount for custom elements' , ( ) => {
636
+ expect ( ( ) => {
637
+ for ( let i = 0 ; i < 3 ; i ++ ) {
638
+ const container = document . createElement ( 'div' ) ;
639
+ ReactDOM . render (
640
+ React . createElement (
641
+ 'x-foo-component' ,
642
+ { 'blah" onclick="beevil" noise="hi' : 'selected' } ,
643
+ null ,
644
+ ) ,
645
+ container ,
646
+ ) ;
647
+ expect ( container . firstChild . attributes . length ) . toBe ( 0 ) ;
648
+ ReactDOM . unmountComponentAtNode ( container ) ;
649
+ ReactDOM . render (
650
+ React . createElement (
651
+ 'x-foo-component' ,
652
+ { '></x-foo-component><script>alert("hi")</script>' : 'selected' } ,
653
+ null ,
654
+ ) ,
655
+ container ,
656
+ ) ;
657
+ expect ( container . firstChild . attributes . length ) . toBe ( 0 ) ;
658
+ }
659
+ } ) . toWarnDev ( [
660
+ 'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`' ,
661
+ 'Warning: Invalid attribute name: `></x-foo-component><script>alert("hi")</script>`' ,
662
+ ] ) ;
663
+ } ) ;
664
+
665
+ it ( 'should reject attribute key injection attack on update for regular DOM' , ( ) => {
666
+ expect ( ( ) => {
667
+ for ( let i = 0 ; i < 3 ; i ++ ) {
668
+ const container = document . createElement ( 'div' ) ;
669
+ const beforeUpdate = React . createElement ( 'div' , { } , null ) ;
578
670
ReactDOM . render ( beforeUpdate , container ) ;
671
+ ReactDOM . render (
672
+ React . createElement (
673
+ 'div' ,
674
+ { 'blah" onclick="beevil" noise="hi' : 'selected' } ,
675
+ null ,
676
+ ) ,
677
+ container ,
678
+ ) ;
679
+ expect ( container . firstChild . attributes . length ) . toBe ( 0 ) ;
680
+ ReactDOM . render (
681
+ React . createElement (
682
+ 'div' ,
683
+ { '></div><script>alert("hi")</script>' : 'selected' } ,
684
+ null ,
685
+ ) ,
686
+ container ,
687
+ ) ;
688
+ expect ( container . firstChild . attributes . length ) . toBe ( 0 ) ;
689
+ }
690
+ } ) . toWarnDev ( [
691
+ 'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`' ,
692
+ 'Warning: Invalid attribute name: `></div><script>alert("hi")</script>`' ,
693
+ ] ) ;
694
+ } ) ;
579
695
580
- const afterUpdate = React . createElement (
581
- 'x-foo-component' ,
582
- { 'blah" onclick="beevil" noise="hi' : 'selected' } ,
583
- null ,
696
+ it ( 'should reject attribute key injection attack on update for custom elements' , ( ) => {
697
+ expect ( ( ) => {
698
+ for ( let i = 0 ; i < 3 ; i ++ ) {
699
+ const container = document . createElement ( 'div' ) ;
700
+ const beforeUpdate = React . createElement ( 'x-foo-component' , { } , null ) ;
701
+ ReactDOM . render ( beforeUpdate , container ) ;
702
+ ReactDOM . render (
703
+ React . createElement (
704
+ 'x-foo-component' ,
705
+ { 'blah" onclick="beevil" noise="hi' : 'selected' } ,
706
+ null ,
707
+ ) ,
708
+ container ,
709
+ ) ;
710
+ expect ( container . firstChild . attributes . length ) . toBe ( 0 ) ;
711
+ ReactDOM . render (
712
+ React . createElement (
713
+ 'x-foo-component' ,
714
+ { '></x-foo-component><script>alert("hi")</script>' : 'selected' } ,
715
+ null ,
716
+ ) ,
717
+ container ,
584
718
) ;
585
- ReactDOM . render ( afterUpdate , container ) ;
719
+ expect ( container . firstChild . attributes . length ) . toBe ( 0 ) ;
586
720
}
587
- } ) . toWarnDev (
721
+ } ) . toWarnDev ( [
588
722
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`' ,
589
- ) ;
723
+ 'Warning: Invalid attribute name: `></x-foo-component><script>alert("hi")</script>`' ,
724
+ ] ) ;
590
725
} ) ;
591
726
592
727
it ( 'should update arbitrary attributes for tags containing dashes' , ( ) => {
0 commit comments