{"record":{"id":"d2e45acd521e720b","repo":"oraios/serena","slug":"unsafe-archive-member-member-name-path-traver","errorCode":null,"errorMessage":"Unsafe archive member '{member_name}': path traversal is not allowed","messagePattern":"Unsafe archive member '(.+?)': path traversal is not allowed","errorType":"exception","errorClass":"SolidLSPException","httpStatus":null,"severity":"critical","filePath":"src/solidlsp/ls_utils.py","lineNumber":596,"sourceCode":"        \"\"\"\n        if not allowed_hosts:\n            return\n\n        hostname = urlparse(url).hostname\n        normalized_allowed_hosts = {host.lower() for host in allowed_hosts}\n        if hostname is None or hostname.lower() not in normalized_allowed_hosts:\n            raise SolidLSPException(\n                f\"Refusing to download from host '{hostname or '<unknown>'}'; allowed hosts: {sorted(normalized_allowed_hosts)}\"\n            )\n\n    @staticmethod\n    def _validate_extraction_path(member_name: str, target_path: str) -> str:\n        \"\"\"\n        Validates that an archive member stays within the extraction root and returns its destination path.\n        \"\"\"\n        normalized_parts = Path(member_name).parts\n        if any(part == \"..\" for part in normalized_parts):\n            raise SolidLSPException(f\"Unsafe archive member '{member_name}': path traversal is not allowed\")\n\n        absolute_target_path = os.path.abspath(target_path)\n        absolute_member_path = os.path.abspath(os.path.join(target_path, member_name))\n        if not (absolute_member_path.startswith(absolute_target_path + os.sep) or absolute_member_path == absolute_target_path):\n            raise SolidLSPException(f\"Unsafe archive member '{member_name}': path escapes extraction directory\")\n\n        return absolute_member_path\n\n    @staticmethod\n    def _extract_zip_archive(archive_path: str, target_path: str) -> None:\n        \"\"\"\n        Extracts a ZIP archive safely while preserving Unix permissions when available.\n        \"\"\"\n        with zipfile.ZipFile(archive_path, \"r\") as zip_ref:\n            for zip_info in zip_ref.infolist():\n                extracted_path = FileUtils._validate_extraction_path(zip_info.filename, target_path)\n\n                if zip_info.is_dir():","sourceCodeStart":578,"sourceCodeEnd":614,"githubUrl":"https://github.com/oraios/serena/blob/7fcbca7e62555ec2287ddb2f083caee805848ea6/src/solidlsp/ls_utils.py#L578-L614","documentation":"Raised by _validate_extraction_path when an archive member name contains a '..' path component. This blocks Zip-Slip / path-traversal attacks where a malicious archive writes files outside the extraction directory.","triggerScenarios":"Extracting a zip or tar archive (via _extract_zip_archive/_extract_tar_archive during download_and_extract_archive_verified) whose member entry names include '..' segments, e.g. '../../etc/cron.d/evil'.","commonSituations":"Downloading a language-server archive from an untrusted or compromised source; a mis-packaged archive using '../' in entry names.","solutions":["Obtain the archive from a trusted, official source","Inspect the archive's member names (unzip -l / tar -tf) and repackage or reject archives containing '..' entries","Report the malicious/mispackaged artifact to its maintainer"],"exampleFix":"// before\nmember = \"../../outside/evil.so\"\n// after\nmember = \"lib/evil.so\"  # repackage archive with relative-only paths","handlingStrategy":"validation","validationCode":"import zipfile\nwith zipfile.ZipFile(path) as z:\n    bad = [n for n in z.namelist() if \"..\" in n.split(\"/\")]\nif bad:\n    raise ValueError(f\"archive contains traversal members: {bad}\")","typeGuard":"def archive_is_safe(member_names: list[str]) -> bool:\n    return all(\"..\" not in n.split(\"/\") and not n.startswith(\"/\") for n in member_names)","tryCatchPattern":"try:\n    download_and_extract_archive_verified(url, target, archive_type=\"zip\")\nexcept SolidLSPException as e:\n    if \"path traversal\" in str(e):\n        raise SecurityError(\"refusing malicious archive from \" + url) from e\n    raise","preventionTips":["Only download archives from official, allowlisted sources","Pre-download inspect member names for '..' or absolute paths","Never weaken the validation to 'fix' this error — reject the archive","Verify checksums so archives cannot be swapped in transit"],"tags":["security","zip-slip","path-traversal","archive"],"backgroundTag":"zip-slip-path-traversal","analyzedSha":"7fcbca7e62555ec2287ddb2f083caee805848ea6","analyzedAt":"2026-08-29T00:04:09.619Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}