{"id":"40a0972a1163f806","repo":"pypa/pip","slug":"invalid-member-in-the-tar-file","errorCode":null,"errorMessage":"Invalid member in the tar file {}: {}","messagePattern":"Invalid member in the tar file (.+?): (.+?)","errorType":"exception","errorClass":"InstallationError","httpStatus":null,"severity":"critical","filePath":"src/pip/_internal/utils/unpacking.py","lineNumber":238,"sourceCode":"                    except tarfile.LinkOutsideDestinationError:\n                        if sys.version_info[:3] in {\n                            (3, 9, 17),\n                            (3, 10, 12),\n                            (3, 11, 4),\n                        }:\n                            # The tarfile filter in specific Python versions\n                            # raises LinkOutsideDestinationError on valid input\n                            # (https://github.com/python/cpython/issues/107845)\n                            # Ignore the error there, but do use the\n                            # more lax `tar_filter`\n                            member = tarfile.tar_filter(member, location)\n                        else:\n                            raise\n                except tarfile.TarError as exc:\n                    message = \"Invalid member in the tar file {}: {}\"\n                    # Filter error messages mention the member name.\n                    # No need to add it here.\n                    raise InstallationError(\n                        message.format(\n                            filename,\n                            exc,\n                        )\n                    )\n                if member.isfile() and orig_mode & 0o111:\n                    member.mode = default_mode_plus_executable\n                else:\n                    # See PEP 706 note above.\n                    # The PEP changed this from `int` to `Optional[int]`,\n                    # where None means \"use the default\". Mypy doesn't\n                    # know this yet.\n                    member.mode = None  # type: ignore [assignment]\n                return member\n\n            tar.extractall(location, filter=pip_filter)\n\n    finally:","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_internal/utils/unpacking.py#L220-L256","documentation":"InstallationError raised when extracting a tar archive and the underlying Python tarfile filter raises a TarError (e.g. a member that the data_filter rejects for safety). pip's pip_filter wraps the member extraction; any tarfile.TarError propagates as this user-facing message identifying the archive and the offending member. It is the tar equivalent of the zip path-traversal guard but covers all data_filter violations.","triggerScenarios":"Unpacking a .tar.gz/.tar.bz2/.tar.xz source distribution where a member triggers tarfile's data_filter rejection (link/absolute path traversal, device files, etc.). Triggered from untar_file's pip_filter on Python 3.12+ (or backported filter).","commonSituations":"Malicious sdist; legacy tar with absolute paths; tar containing device nodes; older archive created before PEP 706 filtering conventions.","solutions":["Inspect the tar with `tar -tvf file.tar.gz` and locate the offending member named in the error.","Reject and re-download from a trusted source; verify the hash.","If legitimately benign, rebuild the archive without the offending member.","Keep pip current so its data_filter rules match upstream CPython."],"exampleFix":"// before\nuntar_file('pkg.tar.gz', '/target')  # contains a device node / absolute path\n\n// after\n# rebuild the archive with safe members:\ntar --sort=name --mtime='UTC 1970-01-01' -czf pkg.tar.gz -C src .","handlingStrategy":"validation","validationCode":"import tarfile\ndef tar_is_safe(path: str) -> bool:\n    try:\n        with tarfile.open(path) as t:\n            for m in t.getmembers():\n                if m.name.startswith('/') or '..' in m.name.split('/'):\n                    return False\n                if m.issym() or m.islnk():\n                    if m.linkname.startswith('/') or '..' in m.linkname.split('/'):\n                        return False\n        return True\n    except tarfile.TarError:\n        return False","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Run on Python 3.12+ so pip uses tarfile.data_filter.","Verify sdist hashes from the index.","Reject packages from untrusted mirrors.","Inspect tar contents in CI before install."],"tags":["pip","tar","security","pep706","path-traversal"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}