Skip to content

Limiting the maximum number of tags on Tag.parse_tag() #1220

Closed

Description

@facutuesca

Would it be worth adding a limit to the maximum number of tags parsed in Tag.parse_tag()?. It builds the cartesian product of compressed tag components:

for interpreter in interpreters.split("."):
for abi in abis.split("."):
for platform_ in platforms.split("."):
tags.add(Tag(interpreter, abi, platform_))

The spec does warn about it, but doesn't actually specify a limit for them

This compression scheme can generate large numbers of unsupported tags and “impossible” tags that are supported by no Python implementation e.g. “cp33-cp31u-win64”, so use it sparingly.

Activity

  1. changed the title [-]Limiting the maximum tags on `Tag.parse_tag()`[/-] [+]Limiting the maximum number of tags on `Tag.parse_tag()`[/+] on Jun 3, 2026
  2. brettcannon commented on Jun 3, 2026

    @brettcannon
    Member

    Are you worried about some attack that will exhaust memory?

  3. facutuesca commented on Jun 3, 2026

    @facutuesca
    ContributorAuthor

    Are you worried about some attack that will exhaust memory?

    Not realistically, if we assume we're parsing a maliciously crafted wheel, it'd be limited by the filesystem limits on filename length (usually 255 bytes). You could craft a filename such that it expands to about ~40k tags:

    {name}-{version}-{python}-{abi}-{platform}.whl
    
    a-1-<36 parts>-<36 parts>-<36 parts>.whl
    
    a-1-a.b.c....-a.b.c...-a.b.c....whl
    
    36 * 36 * 36 = 46.656
    

    which shouldn't be huge memory-wise.

    I opened the issue to ask if it makes sense to limit it more from the "there's no good reason to allow it" side than the "this is definitely exploitable" side.

  4. facutuesca commented on Jun 3, 2026

    @facutuesca
    ContributorAuthor

    Mm thinking about it further, it could be that parse_tag() is called with a tag extracted from a string that does not correspond to an actual file in a filesystem (like the URL for a wheel inside a requirements.txt file). So in that case there's no upper limit for the length of the filename.

  5. notatallshaw commented on Jun 3, 2026

    @notatallshaw
    Member

    Ultimately this isn't an issue for packaging, it's callers of packaging processing untrusted data. They would be best processing such data in some kind of time limited and memory limited sandbox.

    To help such users out I think we should add a key word only argument like "maximum_tags”, with either a default of None (unbounded) or some sufficiently large number that is likely to meet all realistic use cases.

  6. brettcannon commented on Jun 4, 2026

    @brettcannon
    Member

    To help such users out I think we should add a key word only argument like "maximum_tags”, with either a default of None (unbounded) or some sufficiently large number that is likely to meet all realistic use cases.

    I was thinking of something similar: a limit keyword-only argument that defaults to None and if set would raise an exception if the limit is hit before completing.

  7. facutuesca commented on Jun 4, 2026

    @facutuesca
    ContributorAuthor

    Makes sense to me, I created a PR for it here: #1224

  8. notatallshaw commented on Jun 11, 2026

    @notatallshaw
    Member

    Do we call parse_tag under the hood in any of our other objects or helper utilities?

    It may change how we need to expose the limit option.

  9. frenzymadness commented on Jul 28, 2026

    @frenzymadness

    I know I'm commenting on an already closed issue, but I think a reasonable limit here might protect many application that uses this. For example pip calls parse_wheel_filename in their Wheel.__init__ and there is currently no way to use this limit for protection. And as @facutuesca pointed out, we are not limited to what filesystems allow us because a crafted requirements.txt file might cause pip to consume hundreds of MBs of memory even before it tries to touch an actual file.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions