# Upload filenames the filesystem cannot hold, and names whose kind a cut could # change. Two reached open() and raised, a 500 with the booth torn down (r3 # heid bug hunt, hulda, 2026-09-24): a NUL, and a name over NAME_MAX (255 # BYTES) that a 200-CHARACTER cap let through. The second round (hulda) found a # surrogate dropped after the dot rule (`.forever`, the keep marker) and a cut # that manufactured `.png`. Every row is a change tests/test_booth.py claims to # forbid. unit = "upload names the filesystem can hold" [[mutation]] label = "a NUL in an upload name reaches open() (ValueError, a 500)" file = "booth/app.py" test = "tests/test_booth.py::test_upload_a_nul_in_a_filename_never_500s" old = ''' base = (name or "").replace("\x00", "").encode("utf-8", "surrogatepass").decode("utf-8", "ignore")''' new = ''' base = (name or "").encode("utf-8", "surrogatepass").decode("utf-8", "ignore")''' [[mutation]] label = "the NUL is stripped after the dot rule (a NUL shields a leading dot)" file = "booth/app.py" test = "tests/test_booth.py::test_safe_upload_name_drops_nul_before_the_dot_rule" old = ''' base = (name or "").replace("\x00", "").encode("utf-8", "surrogatepass").decode("utf-8", "ignore") base = base.replace("\\", "/").split("/")[-1].strip() base = base.lstrip(".") # a leading dot would hide the file from every listing''' new = ''' base = (name or "").encode("utf-8", "surrogatepass").decode("utf-8", "ignore") base = base.replace("\\", "/").split("/")[-1].strip() base = base.lstrip(".").replace("\x00", "") # a leading dot would hide the file from every listing''' [[mutation]] label = "a lone surrogate is dropped after the dot rule (`.forever`, the keep marker, comes out)" file = "booth/app.py" test = "tests/test_booth.py::test_safe_upload_name_drops_every_unencodable_character_before_the_dot_rule" old = ''' base = (name or "").replace("\x00", "").encode("utf-8", "surrogatepass").decode("utf-8", "ignore") base = base.replace("\\", "/").split("/")[-1].strip() base = base.lstrip(".") # a leading dot would hide the file from every listing''' new = ''' base = (name or "").replace("\x00", "") base = base.replace("\\", "/").split("/")[-1].strip() base = base.lstrip(".").encode("utf-8", "surrogatepass").decode("utf-8", "ignore") # a leading dot would hide the file from every listing''' [[mutation]] label = "the cap counts characters, not bytes (ENAMETOOLONG, a 500)" file = "booth/app.py" test = "tests/test_booth.py::test_upload_a_name_over_name_max_in_bytes_never_500s" old = ''' cut = head.encode("utf-8")[:room].decode("utf-8", "ignore") + tail''' new = ''' cut = head[:room] + tail''' [[mutation]] label = "the cut comes out of the whole name (a long .png stops being an image)" file = "booth/app.py" test = "tests/test_booth.py::test_safe_upload_name_keeps_the_extension_through_the_cut" old = ''' head = stem if tail else base''' new = ''' head, tail = base, ""''' [[mutation]] label = "only a 4-byte extension survives the cut (`.jpeg` is lost)" file = "booth/app.py" test = "tests/test_booth.py::test_safe_upload_name_keeps_the_extension_through_the_cut" old = ''' tail = dot + ext if stem and len((dot + ext).encode("utf-8")) <= 16 else ""''' new = ''' tail = dot + ext if stem and len((dot + ext).encode("utf-8")) <= 4 else ""''' [[mutation]] label = "a cut may land on a shorter suffix and manufacture a kind (`….png` out of `….pngxxx…`)" file = "booth/app.py" test = "tests/test_booth.py::test_safe_upload_name_never_manufactures_a_kind" old = ''' if (classify(cut), doc_kind(cut)) != (classify(base), doc_kind(base)): cut = cut.replace(".", "_")''' new = ''' '''