{"title":"Zip Slip via Unsafe tarfile Extraction","language":"Python","severity":"Critical","cwe":"CWE-22","source_lines":[6],"flow_lines":[6,8,9],"sink_lines":[9],"vulnerable_code":"import tarfile\nimport os\n\ndef deploy_ml_model_package(model_archive_path, deployment_dir):\n    with tarfile.open(model_archive_path, 'r:gz') as tar:\n        for member in tar.getmembers():\n            if member.name.endswith('.pkl') or member.name.endswith('.h5'):\n                target_path = os.path.join(deployment_dir, member.name)\n                tar.extract(member, path=deployment_dir)\n                print(f\"Deployed model file: {target_path}\")\n    return True","explanation":"The code is vulnerable to Zip Slip/Path Traversal attacks because it extracts tar archive members without validating or sanitizing member.name before using it in os.path.join(). An attacker can craft a malicious archive with member names containing '../' sequences to write files outside the intended deployment_dir, potentially overwriting system files or injecting malicious code.","remediation":"The fix resolves both the member name and the deployment directory to their real absolute paths, then verifies that the resolved target path starts with the deployment directory prefix. This prevents path traversal attacks where member.name contains '../' sequences or absolute paths that would write files outside the intended directory. Additionally, the member name is normalized before extraction to strip any traversal components.","secure_code":"import tarfile\nimport os\n\ndef deploy_ml_model_package(model_archive_path, deployment_dir):\n    deployment_dir = os.path.realpath(deployment_dir)\n    with tarfile.open(model_archive_path, 'r:gz') as tar:\n        for member in tar.getmembers():\n            if member.name.endswith('.pkl') or member.name.endswith('.h5'):\n                # Sanitize: resolve the target path and ensure it stays within deployment_dir\n                member_path = os.path.normpath(member.name)\n                # Reject any path that attempts directory traversal\n                if member_path.startswith('..') or os.path.isabs(member_path):\n                    print(f\"Skipping potentially malicious path: {member.name}\")\n                    continue\n                target_path = os.path.realpath(os.path.join(deployment_dir, member_path))\n                if not target_path.startswith(deployment_dir + os.sep) and target_path != deployment_dir:\n                    print(f\"Skipping path traversal attempt: {member.name}\")\n                    continue\n                # Sanitize the member name before extraction\n                member.name = member_path\n                tar.extract(member, path=deployment_dir)\n                print(f\"Deployed model file: {target_path}\")\n    return True"}