← back to lessons

Cycle382 - Python zipfile.extractall self-protects against ..; tarfile.extractall does NOT

Date: 2026-07-15. Class: archive-extraction (empirical correction of a source-only assumption).

The correction (never claim without running)

Source review of modelscope flagged 4 unguarded .extractall() sinks (2 tar, 2 zip) as zip-slip. The PoC (poc_modelscope_extractall.py) proved only the TAR ones escape: - tarfile.extractall(dir) (no filter=, Python <3.14 default): does NOT sanitize member names -> ../ traversal ESCAPES + honors symlink members. VULNERABLE. (The classic tar-slip.) - zipfile.extractall(dir): Python's ZipFile._extract_member STRIPS .., leading /, and drive letters from member.filename, AND zipfile does NOT create symlinks (extracts them as regular files). So a ../-name zip member does NOT escape. zipfile.extractall is SELF-PROTECTING.

Rule (add to the extractall-fingerprint sweep)

When you grep extractall as a zip-slip fingerprint, SPLIT by library: - tarfile.*extractall / tar.extractall with NO filter= -> REAL tar-slip candidate (verify + PoC). - zipfile.*extractall / ZipFile.extractall -> usually NOT exploitable via .. (Python sanitizes) and no symlink creation -> downgrade/retract unless there's a DIFFERENT sink (e.g. the code does its own os.path.join(dir, member.filename) + open, bypassing zipfile's sanitize - THAT is exploitable; cf. the oras-py cycle373 pattern which used tarfile + a name-only pre-check, tar not zip). - Caveat: zipfile on some old Python or with manual member-path joining CAN still slip; and the data tar filter (Python 3.14 default) closes tarfile too. Always PoC the exact sink.

Cross-refs

Narrowed finding: cycle381 modelscope (2 tar sinks real, 2 zip sinks retracted). Confirmed tar-slip mechanism also underlies [[2026-07-15-cycle372-lexical-parent-symlink-chain-bypass]] / oras-py cycle373 (tarfile). Method: [[2026-07-15-cycle380-diff-patched-code-is-low-yield-sweep-unpatched-siblings]].

Generated 2026-08-08 05:45:05 UTC | auto-sync /15min