@@ -749,17 +749,44 @@ def test_upload_download_file(
749749 assert downloaded_file .read_text () == exp_contents
750750
751751
752+ @pytest .mark .parametrize (
753+ ("exp_name" , "exp_contents" , "expect_attachment" , "expected_mime_type" ),
754+ [
755+ (
756+ "malicious.html" ,
757+ "<html><body><script>alert('xss')</script></body></html>" ,
758+ True ,
759+ "text/html; charset=utf-8" ,
760+ ),
761+ ("document.pdf" , "%PDF-1.4 fake pdf contents" , False , "application/pdf" ),
762+ ("readme.txt" , "plain text contents" , True , "text/plain; charset=utf-8" ),
763+ ],
764+ ids = ["html" , "pdf" , "txt" ],
765+ )
752766def test_uploaded_file_security_headers (
753767 tmp_path ,
754768 upload_file : AppHarness ,
755769 driver : WebDriver ,
770+ exp_name : str ,
771+ exp_contents : str ,
772+ expect_attachment : bool ,
773+ expected_mime_type : str ,
756774):
757- """Upload an HTML file and verify security headers prevent inline rendering.
775+ """Upload a file and verify security headers on the served response.
776+
777+ For non-PDF files, Content-Disposition: attachment must be set to force a
778+ download. For PDF files, Content-Disposition must NOT be set so the browser
779+ can render them inline, but Content-Type: application/pdf is always present.
780+ X-Content-Type-Options: nosniff is always required.
758781
759782 Args:
760783 tmp_path: pytest tmp_path fixture
761784 upload_file: harness for UploadFile app.
762785 driver: WebDriver instance.
786+ exp_name: filename to upload.
787+ exp_contents: file contents to upload.
788+ expect_attachment: whether the response should force a download.
789+ expected_mime_type: expected Content-Type mime type.
763790 """
764791 import httpx
765792 from reflex_base .config import get_config
@@ -772,8 +799,6 @@ def test_uploaded_file_security_headers(
772799 upload_box = driver .find_elements (By .XPATH , "//input[@type='file']" )[2 ]
773800 upload_button = driver .find_element (By .ID , "upload_button_tertiary" )
774801
775- exp_name = "malicious.html"
776- exp_contents = "<html><body><script>alert('xss')</script></body></html>"
777802 target_file = tmp_path / exp_name
778803 target_file .write_text (exp_contents )
779804
@@ -788,8 +813,17 @@ def test_uploaded_file_security_headers(
788813 resp = httpx .get (upload_url )
789814 assert resp .status_code == 200
790815 assert resp .text == exp_contents
791- assert resp .headers ["content-disposition" ] == "attachment"
792816 assert resp .headers ["x-content-type-options" ] == "nosniff"
817+ assert resp .headers ["content-type" ] == expected_mime_type
818+
819+ if expect_attachment :
820+ assert resp .headers ["content-disposition" ] == "attachment"
821+ else :
822+ assert "content-disposition" not in resp .headers
823+
824+ if not expect_attachment :
825+ # PDF: no browser download test needed, skip the rest.
826+ return
793827
794828 # Configure the download directory using CDP.
795829 download_dir = tmp_path / "downloads"
0 commit comments