From 3042532c0c45d976f3142ae6e1ec791e493ee84b Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Thu, 15 Oct 2026 19:28:02 +0300 Subject: [PATCH] fix: a symlinked folder aliasing a sibling is listed under both names; an undequantizable gguf tensor type names the file (attacker round 13) Co-Authored-By: Claude Sonnet 5.5 --- modules/loaders/gguf_support.py | 15 ++++++++------- modules/loaders/tests/test_gguf_support.py | 11 ++++++++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/modules/loaders/gguf_support.py b/modules/loaders/gguf_support.py index 86583158..a6d6606c 100644 --- a/modules/loaders/gguf_support.py +++ b/modules/loaders/gguf_support.py @@ -90,13 +90,10 @@ def gguf_names(folder: str) -> list[str]: for root in roots: if not root or not os.path.isdir(root): continue - walked: set[str] = set() for dirpath, dirs, files in os.walk(root, followlinks=True): - real = os.path.realpath(dirpath) - if real in walked: # a symlink loop: this folder was already listed - dirs[:] = [] - continue - walked.add(real) + here = os.path.realpath(dirpath) + os.sep + # a link back to this folder or one above it is a loop; a link to a sibling folder is just a second name + dirs[:] = [d for d in dirs if not here.startswith(os.path.realpath(os.path.join(dirpath, d)) + os.sep)] for f in files: if not is_gguf(f): continue @@ -325,7 +322,11 @@ def _load_native(path: str, pack: bool = False) -> tuple[dict, dict, str]: else: # gguf.quants.dequantize is the reference implementation for every # type the package knows -- do not reimplement it per quant type. - arr = gguf.quants.dequantize(tensor.data, qtype) + try: + arr = gguf.quants.dequantize(tensor.data, qtype) + except NotImplementedError as e: + raise RuntimeError(f"{os.path.basename(path)}: tensor {name!r} uses a storage type the gguf package cannot " + f"dequantize ({e}).") from e quantized += 1 t = torch.from_numpy(arr.copy()) # GGUF stores dimensions in the opposite order to torch. diff --git a/modules/loaders/tests/test_gguf_support.py b/modules/loaders/tests/test_gguf_support.py index 091a3bc6..501f3b37 100644 --- a/modules/loaders/tests/test_gguf_support.py +++ b/modules/loaders/tests/test_gguf_support.py @@ -374,9 +374,18 @@ def test_symlink_loops_do_not_hang_the_listing_and_dotdot_after_a_link_is_refuse enc = fake_folders / "text_encoders" (enc / "a").symlink_to(enc) (enc / "b").symlink_to(enc) - assert gguf_support.gguf_names("text_encoders") == ["a/gemma-Q5_K.gguf"] or "gemma-Q5_K.gguf" in gguf_support.gguf_names("text_encoders") + assert gguf_support.gguf_names("text_encoders") == ["gemma-Q5_K.gguf"] (fake_folders / "outside").mkdir() (fake_folders / "outside" / "inner").mkdir() (fake_folders / "outside" / "s.gguf").write_bytes(b"x") (enc / "lnk").symlink_to(fake_folders / "outside" / "inner") assert gguf_support.gguf_path("text_encoders", "lnk/../s.gguf") is None + + +def test_a_symlinked_folder_aliasing_a_sibling_is_listed_under_both_names(fake_folders): + enc = fake_folders / "text_encoders" + (enc / "gemma").mkdir() + (enc / "gemma" / "g-Q5.gguf").write_bytes(b"x") + (enc / "current").symlink_to(enc / "gemma") + names = gguf_support.gguf_names("text_encoders") + assert "current/g-Q5.gguf" in names and "gemma/g-Q5.gguf" in names