Skip to content

os.path.realpath() on Windows misresolves a broken symlink reached through a directory symlink #160506

Description

@gpshead

Bug report

Bug description:

On Windows, os.path.realpath() returns the wrong path for a broken relative symlink when the path used to reach it goes through a symlink to a directory. ntpath._readlink_deep() joins the link target to dirname() of the path as given, so a .. in the target removes the directory link's name instead of going up from the directory that contains the link. The join dates from bpo-38453 (GH-16967).

tarfile's data and tar extraction filters use this result to decide where a member will be written. Whoever supplies the archive can make extractall() create a new file outside the destination directory, in a directory that already exists, when the extracting process is able to create symlinks.

# Windows, with permission to create symlinks
import os
os.makedirs(r"C:\work\out")
os.symlink(".", r"C:\work\out\alias", target_is_directory=True)
os.symlink(r"..\outside\new.txt", r"C:\work\out\link")
print(os.path.realpath(r"C:\work\out\link"))
print(os.path.realpath(r"C:\work\out\alias\link"))

Both names are the same link, so both lines should be C:\work\outside\new.txt; the second is C:\work\out\outside\new.txt. Opening either name for writing creates C:\work\outside\new.txt.

An archive with the members alias -> ., alias/link -> ../outside/new.txt and a regular file alias/link is extracted by extractall(r"C:\work\out", filter="data") without error and the file's content ends up in C:\work\outside\new.txt. The same archive with the regular file named link raises OutsideDestinationError.

I have not run this on Windows. The output above comes from running the Windows branch of Lib/ntpath.py and Lib/tarfile.py from main on Linux over stand-ins for the nt functions, and from reading the code. test_realpath_broken_symlinks in test_ntpath already asserts the textual join (broken2, broken3). gh-88102, gh-85035 and gh-110495 are related realpath() issues but do not cover this case.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Other

Linked PRs

Activity

  1. self-assigned this
    on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

OS-windowsstdlibStandard Library Python modules in the Lib/ directorytype-securityA security issue

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions