From 1ac9851e5e3eaf64b6f74878fb0e5569012abc32 Mon Sep 17 00:00:00 2001 From: sysy <2772196789@qq.com> Date: Fri, 3 Jul 2026 12:28:15 -0400 Subject: [PATCH] Fix symlink-following arbitrary file write in archive extraction Extractor.extract() called shutil.rmtree(output_path, ignore_errors=True) before extracting. Since Python 3.8, shutil.rmtree() raises OSError on a symlink pointing to a directory, which ignore_errors=True silently swallows. An attacker with write access to a shared cache directory could pre-plant a symlink at the predictable extraction output path; rmtree would no-op on it, and extraction would then follow the symlink and write archive contents into the attacker-chosen target, yielding arbitrary file write as the victim. The existing safemembers() zip-slip mitigation only validates member names and is blind to the output directory itself being a symlink. Remove the symlink itself before extracting so contents can no longer be written through it. --- src/datasets/utils/extract.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/datasets/utils/extract.py b/src/datasets/utils/extract.py index c9d96284e5a..fc3a6abf410 100644 --- a/src/datasets/utils/extract.py +++ b/src/datasets/utils/extract.py @@ -439,6 +439,8 @@ def extract( # Prevent parallel extractions lock_path = str(Path(output_path).with_suffix(".lock")) with FileLock(lock_path): + if os.path.islink(output_path): + os.unlink(output_path) shutil.rmtree(output_path, ignore_errors=True) extractor = cls.extractors[extractor_format] return extractor.extract(input_path, output_path)