Skip to content

Fix fail-open ZIP iteration in _iterate_models (BadZipFile bypass)#355

Open
AAtomical wants to merge 1 commit into
protectai:mainfrom
AAtomical:fix/iterate-models-failopen-badzip
Open

Fix fail-open ZIP iteration in _iterate_models (BadZipFile bypass)#355
AAtomical wants to merge 1 commit into
protectai:mainfrom
AAtomical:fix/iterate-models-failopen-badzip

Conversation

@AAtomical

Copy link
Copy Markdown

_iterate_models() wrapped the entire inner-ZIP entry loop in a single except (zipfile.BadZipFile, RuntimeError). If any one entry raised BadZipFile on zip.open() (e.g. a corrupted local file header), the exception aborted enumeration of the whole archive: every entry after the bad one was silently dropped and never scanned.

A crafted archive can exploit this by placing a corrupted entry before archive/data.pkl in the namelist. modelscan aborts on the corrupted entry and reports 0 issues (CLEAN), while a consumer (torch.load / pickle.load) reads archive/data.pkl directly by name from the intact central directory and executes the malicious pickle -> RCE.

Move the per-entry handling into its own try/except so a single unreadable entry is recorded as skipped (with its source) and iteration continues to the remaining entries. The outer handler is kept for an archive whose central directory itself is unreadable.

Fixes #354

_iterate_models() wrapped the entire inner-ZIP entry loop in a single
`except (zipfile.BadZipFile, RuntimeError)`. If any one entry raised
BadZipFile on `zip.open()` (e.g. a corrupted local file header), the
exception aborted enumeration of the whole archive: every entry after
the bad one was silently dropped and never scanned.

A crafted archive can exploit this by placing a corrupted entry before
`archive/data.pkl` in the namelist. modelscan aborts on the corrupted
entry and reports 0 issues (CLEAN), while a consumer (`torch.load` /
`pickle.load`) reads `archive/data.pkl` directly by name from the intact
central directory and executes the malicious pickle -> RCE.

Move the per-entry handling into its own try/except so a single
unreadable entry is recorded as skipped (with its source) and iteration
continues to the remaining entries. The outer handler is kept for an
archive whose central directory itself is unreadable.

Fixes protectai#354
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fail-open ZIP iterator in _iterate_models allows malicious archive/data.pkl to bypass all scanning

1 participant