Skip to content

Commit aae9e6f

Browse files
committed
Fix: SafeTarExtractor may silently accept truncated members when member.size metadata is incorrect
1 parent 8cc3e31 commit aae9e6f

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

security/tar_safe.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,10 @@ def _extract_file(
197197
while bytes_copied < member.size:
198198
chunk = src.read(min(chunk_size, member.size - bytes_copied))
199199
if not chunk:
200-
break
200+
raise UnsafeTarError(
201+
f"Truncated file: {member.name} - expected {member.size} bytes, "
202+
f"got {bytes_copied}"
203+
)
201204
bytes_copied += len(chunk)
202205
tmp.write(chunk)
203206

tests/test_security.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,27 @@ def test_nested_valid_directories(self, tmp_path):
217217
assert len(extracted) == 1
218218
assert (extract_dir / 'dir1' / 'dir2' / 'file.txt').exists()
219219

220+
def test_truncated_file_detection(self, tmp_path):
221+
"""Test that truncated files (size metadata > actual data) are detected."""
222+
tar_file = tmp_path / "truncated.tar"
223+
224+
with tarfile.open(tar_file, 'w') as tar:
225+
info = tarfile.TarInfo(name='truncated.txt')
226+
info.size = 1000
227+
info.type = tarfile.REGTYPE
228+
content = b'x' * 1000
229+
fileobj = io.BytesIO(content)
230+
tar.addfile(info, fileobj)
231+
232+
data = tar_file.read_bytes()
233+
tar_file.write_bytes(data[:512 + 500])
234+
235+
extract_dir = tmp_path / "extracted"
236+
extractor = SafeTarExtractor()
237+
238+
with pytest.raises(UnsafeTarError):
239+
extractor.extract(tar_file, extract_dir)
240+
220241
def test_size_limits(self, tmp_path):
221242
"""Test file size limits."""
222243
tar_file = tmp_path / "large.tar"

0 commit comments

Comments
 (0)