GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows by serhiy-storchaka · Pull Request #146591 · python/cpython

Conversation

@serhiy-storchaka

@serhiy-storchaka serhiy-storchaka commented Mar 29, 2026 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Use ZipFile.extractall() to sanitize file names and extract files.

Files with invalid names (e.g. absolute paths) are now skipped.

Files containing ".." in the name are no longer skipped.

  • Issue: shutil.unpack_archive() on Windows writes outside extract_dir for ZIP entries with drive-prefixed names #146581

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
serhiy-storchaka added 6 commits February 27, 2026 12:11
@serhiy-storchaka
Fix vulnerability in shutil.unpack_archive() in ZIP files
7c5ad11
Use ZipFile.extractall() to sanitize file names and extract files.

Files with invalid names (e.g. absolute paths) are now extracted with
different names instead of been skipped or written out of the destination
directory.

Files containing ".." in the name are no longer skipped.
@serhiy-storchaka
Preserve the current behavior whether it is possible.
8d0ade5
@serhiy-storchaka
Preserve the current behavior whether it is possible.
7940084
@serhiy-storchaka
Merge remote-tracking branch 'refs/remotes/origin/shutil-unpack_archi…
faddc67
…ve-extractall' into shutil-unpack_archive-extractall
@serhiy-storchaka
Merge branch 'main' into shutil-unpack_archive-extractall
76797cc
@serhiy-storchaka
Add a NEWS entry.
12cf735
@serhiy-storchaka
serhiy-storchaka requested a review from giampaolo as a code owner March 29, 2026 09:57
@serhiy-storchaka serhiy-storchaka added type-security A security issue needs backport to 3.10 needs backport to 3.11 only security fixes needs backport to 3.12 only security fixes needs backport to 3.13 only security fixes needs backport to 3.14 bugs and security fixes labels Mar 29, 2026
@bedevere-app bedevere-app Bot mentioned this pull request Mar 29, 2026
shutil.unpack_archive() on Windows writes outside extract_dir for ZIP entries with drive-prefixed names #146581
Closed
@bedevere-app bedevere-app Bot added the awaiting core review label Mar 29, 2026
@serhiy-storchaka
serhiy-storchaka requested review from sethmlarson and zooba March 29, 2026 09:59
@StanFromIreland StanFromIreland mentioned this pull request Mar 29, 2026
gh-146581: Use ZipFile.extractall() in shutil for secure ZIP extraction #146588
Closed
@Shrey-N

Shrey-N commented Mar 29, 2026

Copy link
Copy Markdown
Contributor

Wasn't os.path.splitroot() introduced in 3.12? if it is backported wouldn't it crash with AttributeError?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Shrey-N

Shrey-N commented Mar 29, 2026

Copy link
Copy Markdown
Contributor

Also, the new os.path.pardir check misses backslash based traversals on Linux/macOS.
The old substring check if '..' in name caught these, but the new component based check treats that whole string as a single (but malicious) filename.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@serhiy-storchaka

serhiy-storchaka commented Mar 29, 2026

Copy link
Copy Markdown
Member Author

Wasn't os.path.splitroot() introduced in 3.12? if it is backported wouldn't it crash with AttributeError?

Backports will be fixed to use equivalent code.

Also, the new os.path.pardir check misses backslash based traversals on Linux/macOS.

Backslash is not a separator on Posix. It is a legal character which has no special meaning.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Shrey-N

Shrey-N commented Mar 29, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

I believe it’s actually a regression. Currently, shutil uses a substring check which correctly catches and skips these backslash traversals on Linux.

In this PR it switches to a component based check, which removes that existing protection.

So I believe this actually reduces the existing security strictness for non windows users

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@serhiy-storchaka

serhiy-storchaka commented Mar 30, 2026

Copy link
Copy Markdown
Member Author

There is no backslash traversal on Linux.

Shrey-N reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

zooba
zooba approved these changes Apr 14, 2026
View reviewed changes
Comment thread Lib/zipfile/__init__.py

fp = None # Set here since __del__ checks it
_windows_illegal_name_trans_table = None
_ignore_invalid_names = False

@zooba zooba Apr 14, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intended to be set by users needing back-compat as well? Should we document it (carefully)?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@serhiy-storchaka serhiy-storchaka Apr 15, 2026

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is intended for internal use in shutil.unpack_archive() only.

We could add it as optional parameter, but this does not look like a good long term solution. Even if we make the parameter name underscored, it will be visible in the help, and will confuse users. Users will start to use it, so it will be difficult to get rid of it.

I think that in future versions we can add a hook which would be called for all entry names. It would allow to translate them to valid paths, allow to skip them (with possible logging) or raise an exception. But this is a new feature, it cannot be backported. And it needs a separate discussion.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting core review labels Apr 14, 2026
@serhiy-storchaka
serhiy-storchaka merged commit fc829e8 into python:main Apr 27, 2026
110 of 112 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@miss-islington-app

miss-islington-app Bot commented Apr 27, 2026

Copy link
Copy Markdown

Thanks @serhiy-storchaka for the PR 🌮🎉.. I'm working now to backport this PR to: 3.10, 3.11, 3.12, 3.13, 3.14.
🐍🍒⛏🤖

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting merge label Apr 27, 2026
@serhiy-storchaka
serhiy-storchaka deleted the shutil-unpack_archive-extractall branch April 27, 2026 18:43
@bedevere-app

bedevere-app Bot commented Apr 27, 2026

Copy link
Copy Markdown

GH-149064 is a backport of this pull request to the 3.14 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label Apr 27, 2026
@bedevere-app

bedevere-app Bot commented Apr 27, 2026

Copy link
Copy Markdown

GH-149065 is a backport of this pull request to the 3.13 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.13 only security fixes label Apr 27, 2026
@miss-islington-app

miss-islington-app Bot commented Apr 27, 2026

Copy link
Copy Markdown

Sorry, @serhiy-storchaka, I could not cleanly backport this to 3.11 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker fc829e88753858c8ac669594bf0093f44948c0f4 3.11
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app

bedevere-app Bot commented Apr 27, 2026

Copy link
Copy Markdown

GH-149066 is a backport of this pull request to the 3.12 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@miss-islington-app miss-islington-app Bot assigned serhiy-storchaka Apr 27, 2026
@bedevere-app bedevere-app Bot removed the needs backport to 3.12 only security fixes label Apr 27, 2026
@miss-islington-app

miss-islington-app Bot commented Apr 27, 2026

Copy link
Copy Markdown

Sorry, @serhiy-storchaka, I could not cleanly backport this to 3.10 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker fc829e88753858c8ac669594bf0093f44948c0f4 3.10
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app

bedevere-app Bot commented Apr 27, 2026

Copy link
Copy Markdown

GH-149071 is a backport of this pull request to the 3.11 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.11 only security fixes label Apr 27, 2026
serhiy-storchaka added a commit that referenced this pull request Apr 27, 2026
@miss-islington @serhiy-storchaka
[3.13] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZI…
ab5ef98
…P files on Windows (GH-146591) (GH-149065)

Use ZipFile.extractall() to sanitize file names and extract files.

Files with invalid names (e.g. absolute paths) are now skipped.

Files containing ".." in the name are no longer skipped.
(cherry picked from commit fc829e8)

Co-authored-by: Serhiy Storchaka <[email protected]>
serhiy-storchaka added a commit that referenced this pull request Apr 27, 2026
@miss-islington @serhiy-storchaka
[3.14] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZI…
b01e594
…P files on Windows (GH-146591) (GH-149064)

Use ZipFile.extractall() to sanitize file names and extract files.

Files with invalid names (e.g. absolute paths) are now skipped.

Files containing ".." in the name are no longer skipped.
(cherry picked from commit fc829e8)

Co-authored-by: Serhiy Storchaka <[email protected]>
@serhiy-storchaka serhiy-storchaka removed the needs backport to 3.10 label Apr 27, 2026
@serhiy-storchaka serhiy-storchaka removed their assignment Apr 27, 2026
This was referenced May 18, 2026
gh-111791: delegating extraction to zipfile module's extractall() method #111824
Closed
shutil.unpack_archive skips false negatives containing '..' #111791
Closed
@gaborbernat gaborbernat mentioned this pull request Jun 3, 2026
Remove private stdlib helpers orphaned by past removals #150882
Closed
gaborbernat added a commit to gaborbernat/cpython that referenced this pull request Jun 3, 2026
@gaborbernat
pythongh-150882: Remove unused shutil._ensure_directory
448cb74
Introduced in python#8295 alongside shutil.unpack_archive() as a helper that
created the parent directory of each extracted member.

Orphaned by pythongh-146581 (pythonGH-146591), the ZIP path-traversal fix, which
reworked _unpack_zipfile() to create directories inline and deleted the
last _ensure_directory(targetpath) call site in the same change.

Since then the private helper has had no caller: a word-boundary search
across Lib, Modules, Python, Objects and Include finds zero references
outside its own definition, and a GitHub code search finds no downstream
importers.
This was referenced Jun 3, 2026
gh-150885: Remove unused shutil._ensure_directory #150883
Merged
Remove unused private function shutil._ensure_directory #150885
Closed
gaborbernat added a commit to gaborbernat/cpython that referenced this pull request Jun 3, 2026
@gaborbernat
pythongh-150885: Remove unused shutil._ensure_directory
5de9387
Introduced in python#8295 alongside shutil.unpack_archive() as a helper that
created the parent directory of each extracted member.

Orphaned by pythongh-146581 (pythonGH-146591), the ZIP path-traversal fix, which
reworked _unpack_zipfile() to create directories inline and deleted the
last _ensure_directory(targetpath) call site in the same change.

Since then the private helper has had no caller: a word-boundary search
across Lib, Modules, Python, Objects and Include finds zero references
outside its own definition, and a GitHub code search finds no downstream
importers.
serhiy-storchaka pushed a commit that referenced this pull request Jun 7, 2026
@gaborbernat
gh-150885: Remove unused shutil._ensure_directory (GH-150883)
e5ced1f
No longer used after gh-146581 (GH-146591).
philthompson10 pushed a commit to philthompson10/cpython that referenced this pull request Jun 17, 2026
@gaborbernat @philthompson10
pythongh-150885: Remove unused shutil._ensure_directory (pythonGH-150883
77b5cd3
)

No longer used after pythongh-146581 (pythonGH-146591).
Yhg1s pushed a commit that referenced this pull request Aug 4, 2026
@miss-islington @serhiy-storchaka
[3.12] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZI…
a6650a2
…P files on Windows (GH-146591) (#149066)

gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (GH-146591)

Use ZipFile.extractall() to sanitize file names and extract files.

Files with invalid names (e.g. absolute paths) are now skipped.

Files containing ".." in the name are no longer skipped.
(cherry picked from commit fc829e8)

Co-authored-by: Serhiy Storchaka <[email protected]>
pablogsal pushed a commit that referenced this pull request Aug 9, 2026
@serhiy-storchaka
[3.11] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZI…
7ef7dd0
…P files on Windows (GH-146591) (#149071)

gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (GH-146591)

Use ZipFile.extractall() to sanitize file names and extract files.

Files with invalid names (e.g. absolute paths) are now skipped.

Files containing ".." in the name are no longer skipped.

(cherry picked from commit fc829e8)
@miss-islington miss-islington mentioned this pull request Aug 9, 2026
[3.10] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (GH-146591) (GH-149071) #155440
Merged
pablogsal pushed a commit that referenced this pull request Aug 10, 2026
@miss-islington @serhiy-storchaka
[3.10] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZI…
1071290
…P files on Windows (GH-146591) (GH-149071) (#155440)

[3.11] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (GH-146591) (GH-149071)

gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (GH-146591)

Use ZipFile.extractall() to sanitize file names and extract files.

Files with invalid names (e.g. absolute paths) are now skipped.

Files containing ".." in the name are no longer skipped.
(cherry picked from commit 7ef7dd0)


(cherry picked from commit fc829e8)

Co-authored-by: Serhiy Storchaka <[email protected]>
icanhasmath pushed a commit to ActiveState/cpython that referenced this pull request Oct 28, 2026
@miss-islington @serhiy-storchaka @icanhasmath
[3.10] pythongh-146581: Fix vulnerability in shutil.unpack_archive() …
906bb52
…for ZIP files on Windows (pythonGH-146591) (pythonGH-149071) (python#155440)

[3.11] pythongh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (pythonGH-146591) (pythonGH-149071)

pythongh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (pythonGH-146591)

Use ZipFile.extractall() to sanitize file names and extract files.

Files with invalid names (e.g. absolute paths) are now skipped.

Files containing ".." in the name are no longer skipped.
(cherry picked from commit 7ef7dd0)

(cherry picked from commit fc829e8)

Co-authored-by: Serhiy Storchaka <[email protected]>
(cherry picked from commit 1071290)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@zooba zooba zooba approved these changes
@giampaolo giampaolo Awaiting requested review from giampaolo giampaolo is a code owner
@sethmlarson sethmlarson Awaiting requested review from sethmlarson

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

type-security A security issue

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@serhiy-storchaka @Shrey-N @zooba
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.