@@ -701,6 +701,119 @@ def test_static_notebook_template_with_nonexistent_custom_css(
701701        assert  "<style title='marimo-custom'>"  not  in result 
702702        _assert_no_leftover_replacements (result )
703703
704+     def  test_static_files_injection_prevention (self ) ->  None :
705+         """Test that malicious content in files dict doesn't enable script breakout.""" 
706+         # Test with malicious file keys and values 
707+         malicious_files  =  {
708+             "normal.txt" : "safe content" ,
709+             "</script><script>alert(1)</script>" : "content" ,
710+             "file.js" : "</script><img src=x onerror=alert(1)>" ,
711+             "test&<>.py" : "content with <script>alert(1)</script>" ,
712+         }
713+ 
714+         result  =  templates .static_notebook_template (
715+             self .html ,
716+             self .user_config ,
717+             self .config_overrides ,
718+             self .server_token ,
719+             self .app_config ,
720+             self .filepath ,
721+             self .code ,
722+             hash_code (self .code ),
723+             self .session_snapshot ,
724+             self .notebook_snapshot ,
725+             malicious_files ,
726+         )
727+ 
728+         # Must not contain unescaped script breakout sequences (< and > escaped) 
729+         assert  "</script><script>alert(1)"  not  in result 
730+         assert  "<img"  not  in result   # The < should be escaped 
731+ 
732+         # Must contain escaped versions of < and > 
733+         assert  "\\ u003C"  in  result  or  "\\ u003E"  in  result 
734+ 
735+         # Must still be valid HTML 
736+         _assert_no_leftover_replacements (result )
737+ 
738+     def  test_static_malicious_filename_injection (self ) ->  None :
739+         """Test that malicious filenames in static exports are properly escaped.""" 
740+         malicious_filepath  =  self .tmp_path  /  "</script><script>alert(1)</script>.py" 
741+ 
742+         result  =  templates .static_notebook_template (
743+             self .html ,
744+             self .user_config ,
745+             self .config_overrides ,
746+             self .server_token ,
747+             self .app_config ,
748+             str (malicious_filepath ),
749+             self .code ,
750+             hash_code (self .code ),
751+             self .session_snapshot ,
752+             self .notebook_snapshot ,
753+             self .files ,
754+         )
755+ 
756+         # Must not contain unescaped script tags 
757+         assert  "</script><script>"  not  in result 
758+         assert  "<script>alert(1)"  not  in result .replace ("\\ u003Cscript\\ u003E" , "" )
759+ 
760+         # Must contain escaped versions in JSON context 
761+         assert  "\\ u003C"  in  result  or  "\\ u003E"  in  result 
762+ 
763+         _assert_no_leftover_replacements (result )
764+ 
765+     def  test_static_malicious_code_content (self ) ->  None :
766+         """Test that malicious code content is properly escaped in static export.""" 
767+         malicious_code  =  """ 
768+ import marimo as mo 
769+ # This code contains </script><script>alert('XSS')</script> 
770+ mo.md("<img src=x onerror=alert(1)>") 
771+ """ 
772+ 
773+         # Create session with malicious code in output 
774+         malicious_session  =  NotebookSessionV1 (
775+             version = VERSION ,
776+             metadata = NotebookSessionMetadata (marimo_version = "0.1.0" ),
777+             cells = [
778+                 Cell (
779+                     cell_id = "cell1" ,
780+                     code = malicious_code ,
781+                     outputs = [
782+                         DataOutput (
783+                             channel = "output" ,
784+                             mimetype = "text/html" ,
785+                             data = "</script><script>alert(1)</script>" ,
786+                             timestamp = 0.0 ,
787+                         )
788+                     ],
789+                     console = [],
790+                 )
791+             ],
792+         )
793+ 
794+         result  =  templates .static_notebook_template (
795+             self .html ,
796+             self .user_config ,
797+             self .config_overrides ,
798+             self .server_token ,
799+             self .app_config ,
800+             self .filepath ,
801+             malicious_code ,
802+             hash_code (malicious_code ),
803+             malicious_session ,
804+             self .notebook_snapshot ,
805+             self .files ,
806+         )
807+ 
808+         # The malicious code itself should be in JSON context (escaped) 
809+         # Must not have unescaped dangerous sequences in script tags (< and > escaped) 
810+         assert  "</script><script>alert('XSS')"  not  in result 
811+ 
812+         # Must have escaped versions of < and > 
813+         assert  "\\ u003C"  in  result  or  "\\ u003E"  in  result 
814+ 
815+         _assert_no_leftover_replacements (result )
816+ 
704817
705818class  TestWasmNotebookTemplate (unittest .TestCase ):
706819    def  setUp (self ) ->  None :
0 commit comments