@@ -172,6 +172,68 @@ def test_handles_non_utf8_gracefully(self):
172172 result = normalize_csrf_in_body (html )
173173 assert result == html
174174
175+ def test_normalizes_js_csrf_header_assignment_double_quotes (self ):
176+ """JavaScript CSRF header assignment with double quotes should be normalized."""
177+ html = b"""<script>
178+ const requestInterceptor = (request) => {
179+ request.headers["X-CSRFTOKEN"] = "7180AeP5yScQ72FIE7z8tCtrrQc32Sgaqpqgk8ktVXeBXw7a5qDgXoGgLiWF22Ew";
180+ return request;
181+ };
182+ </script>"""
183+ result = normalize_csrf_in_body (html )
184+ assert result is not None
185+ assert CSRF_PLACEHOLDER .encode () in result
186+ assert b"7180AeP5yScQ72FIE7z8tCtrrQc32Sgaqpqgk8ktVXeBXw7a5qDgXoGgLiWF22Ew" not in result
187+
188+ def test_normalizes_js_csrf_header_assignment_single_quotes (self ):
189+ """JavaScript CSRF header assignment with single quotes should be normalized."""
190+ html = b"""<script>
191+ request.headers['X-CSRFTOKEN'] = 'someToken123';
192+ </script>"""
193+ result = normalize_csrf_in_body (html )
194+ assert result is not None
195+ assert CSRF_PLACEHOLDER .encode () in result
196+ assert b"someToken123" not in result
197+
198+ def test_normalizes_js_csrf_header_case_insensitive (self ):
199+ """JavaScript CSRF header matching should be case-insensitive (X-CSRFToken)."""
200+ html = b"""<script>
201+ request.headers["X-CSRFToken"] = "myToken456";
202+ </script>"""
203+ result = normalize_csrf_in_body (html )
204+ assert result is not None
205+ assert CSRF_PLACEHOLDER .encode () in result
206+ assert b"myToken456" not in result
207+
208+ def test_normalizes_js_csrf_header_preserves_surrounding_js (self ):
209+ """Surrounding JavaScript should be preserved when normalizing CSRF header."""
210+ html = b"""<script>
211+ const requestInterceptor = (request) => {
212+ if (!["GET", undefined].includes(request.method)) {
213+ request.headers["X-CSRFTOKEN"] = "tokenABC";
214+ }
215+ return request;
216+ };
217+ </script>"""
218+ result = normalize_csrf_in_body (html )
219+ assert result is not None
220+ assert b"requestInterceptor" in result
221+ assert b"return request" in result
222+ assert CSRF_PLACEHOLDER .encode () in result
223+ assert b"tokenABC" not in result
224+
225+ def test_normalizes_both_form_and_js_csrf_tokens (self ):
226+ """Both form hidden inputs and JS CSRF header assignments should be normalized."""
227+ html = b"""<html>
228+ <form><input name="csrfmiddlewaretoken" value="formToken123"></form>
229+ <script>request.headers["X-CSRFTOKEN"] = "jsToken456";</script>
230+ </html>"""
231+ result = normalize_csrf_in_body (html )
232+ assert result is not None
233+ assert result .count (CSRF_PLACEHOLDER .encode ()) == 2
234+ assert b"formToken123" not in result
235+ assert b"jsToken456" not in result
236+
175237
176238class TestNormalizeHtmlBody :
177239 """Tests for normalize_html_body function."""
0 commit comments