From f3815eb0ce5afd3be8a7f4078fa4ca53f310eebe Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Mon, 30 Mar 2026 09:27:59 -0400 Subject: [PATCH] fix: CWE-407 content length cap on browser form paths; tighten bleach pin; add tests - views/__init__.py: add MAX_CONTENT_LENGTH = 500_000 (shared constant with comment explaining the CWE-407 / bleach ReDoS rationale) - reply_node.py: reject oversized content before set_data() / clean_raw_html() - modify_node.py: same guard on edit path - new_thread.py: same guard on new thread path - requirements.py3.txt: tighten bleach>=2.1.4 -> bleach>=6.0.0 with CVE note - test_render.py: unit tests for bleach version contract, API stability, sanitization correctness, and ReDoS resistance timing - test_views.py: functional tests for content length enforcement on all three browser form paths (reply, new thread) --- remarkbox/tests/test_render.py | 88 ++++++++++++++++++++++++++ remarkbox/tests/test_views.py | 110 +++++++++++++++++++++++++++++++++ remarkbox/views/__init__.py | 8 +++ remarkbox/views/modify_node.py | 9 ++- remarkbox/views/new_thread.py | 9 ++- remarkbox/views/reply_node.py | 8 +++ requirements.py3.txt | 4 +- 7 files changed, 233 insertions(+), 3 deletions(-) diff --git a/remarkbox/tests/test_render.py b/remarkbox/tests/test_render.py index 0091618..2de68b0 100644 --- a/remarkbox/tests/test_render.py +++ b/remarkbox/tests/test_render.py @@ -1,4 +1,6 @@ +import time import unittest +from packaging.version import Version from remarkbox.models import Namespace, User @@ -118,3 +120,89 @@ class TestRenderMarkdown(unittest.TestCase): self.assertIn( '', clean_html ) + + +# --------------------------------------------------------------------------- +# Unit tests: bleach version contract +# +# These tests guard the requirements.py3.txt pin "bleach>=6.0.0". +# bleach < 3.3.0 had unpatched ReDoS (CVE-2021-23980) in its linkifier. +# bleach < 6.0.0 had API differences that break the LinkifyFilter import path +# used in sanitize_html.py. Pinning >=6.0.0 rules out all pre-fix versions. +# --------------------------------------------------------------------------- + +class TestBleachVersionContract(unittest.TestCase): + + def test_bleach_version_gte_6(self): + """Installed bleach must be >= 6.0.0 to rule out CVE-2021-23980 and + earlier linkifier API breakage. If this fails, tighten the pin in + requirements.py3.txt to bleach>=6.0.0.""" + import bleach + self.assertGreaterEqual( + Version(bleach.__version__), + Version("6.0.0"), + "bleach must be >= 6.0.0 (CVE-2021-23980 was fixed in 3.3.0; " + "LinkifyFilter API stabilised in 6.x).", + ) + + def test_linkify_filter_importable(self): + """bleach.linkifier.LinkifyFilter must be importable. + sanitize_html.py depends on this symbol; a bleach upgrade that removes + it would silently break sanitization.""" + from bleach.linkifier import LinkifyFilter # noqa: F401 + + def test_bleach_cleaner_importable(self): + """bleach.sanitizer.Cleaner must be importable.""" + from bleach.sanitizer import Cleaner # noqa: F401 + + +# --------------------------------------------------------------------------- +# Unit tests: sanitization correctness with bleach 6.x +# +# These verify that the behaviours relied upon by clean_raw_html still hold +# after a bleach upgrade: XSS stripping, auto-linkification, nofollow. +# --------------------------------------------------------------------------- + +class TestSanitizationWithBleach6(unittest.TestCase): + + def _clean(self, html, namespace_name="example.com"): + from remarkbox.lib.render import clean_raw_html, make_cleaner_from_namespace + ns = Namespace(namespace_name) + cleaner = make_cleaner_from_namespace(ns) + return clean_raw_html(html, cleaner) + + def test_script_tag_stripped(self): + """") + self.assertNotIn("