{"record":{"id":"092359b37ee68e39","repo":"binary-husky/gpt_academic","slug":"attempted-path-traversal-in-member-name","errorCode":null,"errorMessage":"Attempted Path Traversal in {member.name}","messagePattern":"Attempted Path Traversal in (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"shared_utils/handle_upload.py","lineNumber":143,"sourceCode":"    # Extract the archive based on its extension\n    if file_extension == \".zip\":\n        with zipfile.ZipFile(file_path, \"r\") as zipobj:\n            zipobj._extract_member = lambda a,b,c: zip_extract_member_new(zipobj, a,b,c)    # 修复中文乱码的问题\n            zipobj.extractall(path=dest_dir)\n            logger.info(\"Successfully extracted zip archive to {}\".format(dest_dir))\n\n    elif file_extension in [\".tar\", \".gz\", \".bz2\"]:\n        try:\n            with tarfile.open(file_path, \"r:*\") as tarobj:\n                # 清理提取路径，移除任何不安全的元素\n                for member in tarobj.getmembers():\n                    member_path = os.path.normpath(member.name)\n                    full_path = os.path.join(dest_dir, member_path)\n                    full_path = os.path.abspath(full_path)\n                    if member.islnk() or member.issym():\n                        raise Exception(f\"Attempted Symlink in {member.name}\")\n                    if not full_path.startswith(os.path.abspath(dest_dir) + os.sep):\n                        raise Exception(f\"Attempted Path Traversal in {member.name}\")\n\n                tarobj.extractall(path=dest_dir)\n                logger.info(\"Successfully extracted tar archive to {}\".format(dest_dir))\n        except tarfile.ReadError as e:\n            if file_extension == \".gz\":\n                # 一些特别奇葩的项目，是一个gz文件，里面不是tar，只有一个tex文件\n                import gzip\n                with gzip.open(file_path, 'rb') as f_in:\n                    with open(os.path.join(dest_dir, 'main.tex'), 'wb') as f_out:\n                        f_out.write(f_in.read())\n            else:\n                raise e\n\n    # 第三方库，需要预先pip install rarfile\n    # 此外，Windows上还需要安装winrar软件，配置其Path环境变量，如\"C:\\Program Files\\WinRAR\"才可以\n    elif file_extension == \".rar\":\n        try:\n            import rarfile  # 用来检查rarfile是否安装，不要删除","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/binary-husky/gpt_academic/blob/d6bde0fa54373309bd05823a49bda8da019d2c77/shared_utils/handle_upload.py#L125-L161","documentation":"Companion check to error 198: for each tar member, member.name is normalized, joined with dest_dir, made absolute, and required to stay inside dest_dir + os.sep; otherwise extraction aborts with Exception('Attempted Path Traversal in {member.name}'). This stops '../'-style members from writing outside the extraction directory (zip-slip).","triggerScenarios":"Uploading a tar archive containing member names like '../../etc/cron.d/x' or absolute paths that, after normpath/abspath, resolve outside the destination upload directory.","commonSituations":"Malicious crafted archives targeting the upload handler; rarely, archives built with unusual tooling that emits './'-prefixed or absolute entry names that normalize outside dest_dir; the guard is intentional and should not fire for normal archives.","solutions":["Do not upload the archive; inspect it ('tar -tvf') and remove/rewrite entries with '..' or leading '/' components.","Repack cleanly from a fresh directory (tar -czf from inside the source dir avoids absolute prefixes).","Treat repeated occurrences as a sign of a hostile file — do not whitelist."],"exampleFix":"# shell: inspect and repack safely\n# tar -tvf upload.tar                 # look for ../ or leading /\n# mkdir clean && tar -xzf upload.tar -C clean  # only after manual review\n# (cd clean && tar -czf clean.tar.gz .)","handlingStrategy":"validation","validationCode":"import tarfile, os\n\ndef tar_members_escape(dest_dir: str, path: str) -> list:\n    root = os.path.abspath(dest_dir) + os.sep\n    with tarfile.open(path, 'r:*') as t:\n        return [m.name for m in t.getmembers()\n                if not (os.path.abspath(os.path.join(dest_dir, os.path.normpath(m.name))).startswith(root))]\n\nif tar_members_escape(dest_dir, upload_path):\n    reject_upload('archive contains path traversal entries')","typeGuard":null,"tryCatchPattern":"try:\n    extract_archive(upload_path, dest_dir)\nexcept Exception as e:\n    if 'Attempted Path Traversal' in str(e):\n        quarantine_upload(upload_path)  # suspicious file — flag it\n    else:\n        raise","preventionTips":["Inspect archives with tar -tvf and reject entries containing '..' or leading '/'.","Create archives from inside the source directory to avoid absolute prefixes.","Quarantine, never whitelist, archives that trip this guard."],"tags":["security","archive","tar","path-traversal","zip-slip","upload"],"backgroundTag":null,"analyzedSha":"d6bde0fa54373309bd05823a49bda8da019d2c77","analyzedAt":"2026-08-14T22:48:35.038Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}