Visitar URL original
Deprecate os.path.commonprefix · Issue #74453 · python/cpython · GitHub
Skip to content

Deprecate os.path.commonprefix #74453

Closed
Closed

Description

@progval
mannequin
BPO 30267
Nosy @brettcannon, @rhettinger, @vstinner, @nedbat, @progval, @serhiy-storchaka

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2017-05-04.16:02:33.332>
labels = ['library']
title = 'Deprecate os.path.commonprefix'
updated_at = <Date 2022-02-16.07:38:29.868>
user = 'https://github.com/ProgVal'

bugs.python.org fields:

activity = <Date 2022-02-16.07:38:29.868>
actor = 'serhiy.storchaka'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2017-05-04.16:02:33.332>
creator = 'Valentin.Lorentz'
dependencies = []
files = []
hgrepos = []
issue_num = 30267
keywords = []
message_count = 6.0
messages = ['292993', '292994', '293004', '293140', '293173', '413320']
nosy_count = 6.0
nosy_names = ['brett.cannon', 'rhettinger', 'vstinner', 'nedbat', 'Valentin.Lorentz', 'serhiy.storchaka']
pr_nums = []
priority = 'low'
resolution = None
stage = None
status = 'open'
superseder = None
type = None
url = 'https://bugs.python.org/issue30267'
versions = []

Linked PRs

Activity

  1. progval commented on May 4, 2017

    progvalmannequin
    MannequinAuthor

    The function os.path.commonprefix computes the longest prefix of strings (any iterable, actually), regardless of their meaning as paths.

    I do not see any reason to use this function for paths, and keeping it in the os.path module makes it prone to be confused with os.path.commonpath (which was introduced in Python 3.5).

    I believe making this function raise a DeprecationWarning would help avoid having this kind of bugs.

  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    on May 4, 2017
  3. vstinner commented on May 4, 2017

    @vstinner
    Member

    Ned Batchelder wrote an article about this function in 2010 :-)

    https://nedbatchelder.com/blog/201003/whats_the_point_of_ospathcommonprefix.html

    """
    The docs helpfully include the warning:

    Note that this may return invalid paths because it works a character at a time.
    

    But it should say:

    This function is in the wrong place, and has nothing to do with paths, don't use it if you are interested in file paths!
    

    """

  4. serhiy-storchaka commented on May 4, 2017

    @serhiy-storchaka
    Member

    We shouldn't deprecate a function until add an alternative. There is a working alternative for paths, but commonprefix() is used in the wild for non-paths (for example in unittest.util). The problem is that there is no right place for this function. The string module is wrong place because commonprefix() supports not only strings. Perhaps the new seqtools module would be a right place.

  5. brettcannon commented on May 5, 2017

    @brettcannon
    Member

    I agree with Serhiy that it might be time to create a seqtools module.

  6. rhettinger commented on May 6, 2017

    @rhettinger
    Contributor

    The os.path.commonprefix function has been around for a very long time. Deprecating it will just cause unnecessary pain for users and make it harder to upgrade to Python 3. The function isn't broken, the only issue here is that a new function was added with a similar name.

  7. serhiy-storchaka commented on Feb 16, 2022

    @serhiy-storchaka
    Member

    For now, there are three uses of commonprefix() in the stdlib:

    1. In urllib.request it causes a security issue (see bpo-46756). commonpath() or just str.startswith() should be used instead.

    2. In lib2to3.main. The code contains a workaround around commonprefix(). It could be simplified by using commonpath().

    3. In unittest.util. This is the only correct use of commonprefix(). It cannot be replaced by commonpath().

    I think that we should add commonprefix() in the string module (or maybe in a new module for operations on sequences), deprecate os.path.commonprefix() in documentation only, several versions later add a deprecation warning in os.path.commonprefix(), and several versions later remove os.path.commonprefix().

  8. transferred this issue fromon Apr 10, 2022
  9. gbdlin commented on Jan 8, 2023

    @gbdlin

    In the meantime, maybe that note in the commonprefix documentation entry should be escalated to a security warning?

  10. iritkatriel commented on Feb 18, 2023

    @iritkatriel
    Member

    In the meantime, maybe that note in the commonprefix documentation entry should be escalated to a security warning?

    Why is this a security issue?

  11. vstinner commented on Apr 5, 2023

    @vstinner
    Member

    Why is this a security issue?

    The function can be misused to prevent directory traversal.

  12. brettcannon commented on Apr 6, 2023

    @brettcannon
    Member
  13. barneygale commented on Apr 7, 2023

    @barneygale
    Contributor

    I agree with Ned Batchelder's blog post: "This function is worse than useless, it’s misleading."

    I think that we should add commonprefix() in the string module (or maybe in a new module for operations on sequences), deprecate os.path.commonprefix() in documentation only, several versions later add a deprecation warning in os.path.commonprefix(), and several versions later remove os.path.commonprefix().

    +1 to this.

    I note that os.path.commonprefix() called with no arguments returns the empty string '', which makes me feel slightly better about it going in string rather than a new seqtools module. In a similar vein we have a str.removeprefix() method that works on strings, despite the potential for it to be extended to sequences more generally.

  14. disconnect3d commented on Apr 7, 2023

    @disconnect3d
    Contributor

    Hi,

    Regarding why the os.path.commonprefix may be a security vulnerability, here is an actual case where it (likely, depending on the source of a tar archive) is.

    The os.path.commonprefix function is being used in 61000+ instances of an attempt to fix CVE-2007-4559, the tarfile.extractall path traversal made by the @TrellixVulnTeam [0]. However, apart from being spam (since Trellix hasn't evaluated whether a project needs such a "fix", or didn't bother to sign CLAs etc. [1]), the fix that was made still allows for a path traversal due to the use (or incorrect use) of os.path.commonprefix.

    So what is the issue in that case?

    The TrellixVulnTeam's tar.extractall fix looks as follows:

    with tarfile.open('my.tar') as f:
        def is_within_directory(directory, target):
            abs_directory = os.path.abspath(directory)
            abs_target = os.path.abspath(target)
    
            prefix = os.path.commonprefix([abs_directory, abs_target])
            return prefix == abs_directory
    
        def safe_extract(tar, path=".", members=None, *, numeric_owner=False):
            for member in tar.getmembers():
                member_path = os.path.join(path, member.name)
                if not is_within_directory(path, member_path):
                    raise Exception("Attempted Path Traversal in Tar File")
    
            tar.extractall(path, members, numeric_owner=numeric_owner)
    
        safe_extract(f, tmp_dir)

    Now, this all boils down to the following check:

            prefix = os.path.commonprefix([abs_directory, abs_target])
            return prefix == abs_directory

    The abs_target is just an absolute path from os.path.join(path_to_extract_to, archive_file_member.name) and the problem is that if we know the path we are extracting to, e.g., ./tmp we can then set the member.name to ../tmpXXX and then we will get:

    [*] Will extract archive_file_member.name: ../tmpXXX
    target           = ./tmp/../tmpXXX
    abs_directory    = /Users/dc/playground/py-tarfile-extractall-cve-patch/tmp
    abs_target       = /Users/dc/playground/py-tarfile-extractall-cve-patch/tmpXXX
    prefix           = /Users/dc/playground/py-tarfile-extractall-cve-patch/tmp

    As a result, while we intended to extract the tmpXXX file into ./tmp/tmpXXX, we ended up extracting it to ./tmpXXX and this is because of the os.path.commonprefix used here that made it so that:

    os.path.commonprefix([abs_directory, abs_target])
    ==
    abs_directory, abs_target([
        "/Users/dc/playground/py-tarfile-extractall-cve-patch/tmp",
        "/Users/dc/playground/py-tarfile-extractall-cve-patch/tmpXXX"
    ])
    ==
    "/Users/dc/playground/py-tarfile-extractall-cve-patch/tmp"
    

    which matched the abs_directory being checked in return prefix == abs_directory.

    You can find the full proof of concept from above code here: https://gist.github.com/disconnect3d/00a22838380cd2a29cfc87a8599261f6

    With all that being said, I think it may make sense to add a security warning that the os.path.commonprefix function should not be used for checking paths, giving a counter example like the one shown in this post, even if it is moved to another module/class.

    [0] https://www.trellix.com/en-us/about/newsroom/stories/research/trellix-advanced-research-center-patches-vulnerable-open-source-projects.html
    [1] Among others (I can't list 61k PRs here):

  15. barneygale commented on Apr 7, 2023

    @barneygale
    Contributor

    Q: If we add string.commonprefix(), should it accept a single list of strings, or should it have a signature more like os.path.join, i.e. def commonprefix(s, *strings):?

    I ask because I suspect finding the common prefix of precisely two strings is the most common use case, and users might not anticipate a need to wrap the arguments in a list.

  16. 7 remaining items

  17. added 6 commits that reference this issue on Feb 3, 2026
  18. sethmlarson commented on Feb 3, 2026

    @sethmlarson
    Contributor

    I've created the follow-up PR which deprecates os.path.commonprefix: #144436

  19. added a commit that references this issue on Feb 3, 2026
  20. added a commit that references this issue on Feb 5, 2026
  21. sethmlarson commented on Feb 5, 2026

    @sethmlarson
    Contributor

    This issue is now complete, os.path.commonprefix() is deprecated in Python 3.15.

  22. added 2 commits that reference this issue on Feb 15, 2026
  23. added a commit that references this issue on Apr 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions