{"record":{"id":"d0e7166409284256","repo":"agentscope-ai/agentscope","slug":"unsafe-archive-member-name","errorCode":null,"errorMessage":"unsafe archive member: ' + name","messagePattern":"unsafe archive member: ' \\+ name","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/agentscope/workspace/_base.py","lineNumber":193,"sourceCode":"    \"finally:\\n\"\n    \"    tf.close()\\n\"\n    \"os.unlink(src)\\n\"\n)\n\n#: Expands an archive inside the sandbox. Runs there rather than on the\n#: server so a traversing or bomb-sized archive detonates in the\n#: isolated environment. Argv: src, dst, format, max extracted bytes.\n_EXTRACT_ARCHIVE_SHIM = (\n    \"import os, sys, tarfile, zipfile\\n\"\n    \"src, dst, fmt, limit = sys.argv[1:5]\\n\"\n    \"limit = int(limit)\\n\"\n    \"os.makedirs(dst, exist_ok=True)\\n\"\n    \"dst_real = os.path.realpath(dst)\\n\"\n    \"def check(name):\\n\"\n    \"    target = os.path.realpath(os.path.join(dst, name))\\n\"\n    \"    if not (target == dst_real\"\n    \" or target.startswith(dst_real + os.sep)):\\n\"\n    \"        raise Exception('unsafe archive member: ' + name)\\n\"\n    \"if fmt == 'zip':\\n\"\n    \"    ar = zipfile.ZipFile(src)\\n\"\n    \"    members = ar.infolist()\\n\"\n    \"    total = sum(m.file_size for m in members)\\n\"\n    \"    names = [m.filename for m in members]\\n\"\n    \"else:\\n\"\n    \"    ar = tarfile.open(src)\\n\"\n    \"    members = ar.getmembers()\\n\"\n    \"    total = sum(m.size for m in members)\\n\"\n    \"    names = [m.name for m in members]\\n\"\n    \"    for m in members:\\n\"\n    \"        if m.issym() or m.islnk():\\n\"\n    \"            check(os.path.join(os.path.dirname(m.name), m.linkname))\\n\"\n    \"try:\\n\"\n    \"    if total > limit:\\n\"\n    \"        raise Exception('archive expands to %d bytes, limit is %d'\\n\"\n    \"                        % (total, limit))\\n\"\n    \"    for name in names:\\n\"","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/workspace/_base.py#L175-L211","documentation":"Same Zip-Slip guard as the tar shim, but for the zip/tar archive-expansion shim: each member name (and symlink/hardlink targets) must realpath inside the destination. The member name that failed is included in the message.","triggerScenarios":"add_skill_archive with a zip (or tar) whose entries have names resolving outside the extraction dir — absolute names, ../ segments, or link members whose linkname escapes.","commonSituations":"Zips created on Windows with absolute paths or backslash traversal, downloaded skill archives containing symlinks out of the root, repackaged content from untrusted marketplaces.","solutions":["List the archive contents (`unzip -l skill.zip` / `tar -tvf`) and find the offending entry named in the message","Repack with relative, forward-slash member names","Verify no entry is a symlink pointing outside the archive root","Only install archives from trusted sources"],"exampleFix":"# before: entry 'C:\\\\skills\\\\my\\\\SKILL.md' or '../../x'\n# after: repack so entries are relative\nzip skill.zip SKILL.md assets/ -r  # run from inside the skill dir","handlingStrategy":"validation","validationCode":"import zipfile, tarfile\n\ndef archive_members_safe(path: str) -> bool:\n    if path.endswith('.zip'):\n        names = [m.filename for m in zipfile.ZipFile(path).infolist()]\n    else:\n        names = [m.name for m in tarfile.open(path)]\n    for n in names:\n        if n.startswith(('/', '\\\\')) or '..' in n.replace('\\\\', '/').split('/'):\n            return False\n    return True","typeGuard":null,"tryCatchPattern":"try:\n    await ws.add_skill_archive(path, name)\nexcept ValueError as e:\n    if 'unsafe archive member' in str(e):\n        quarantine(path)  # treat as hostile input\n    raise","preventionTips":["Validate downloaded archives before install","Reject members with absolute paths or '..' segments","Prefer archives produced by standard tools from within the skill dir"],"tags":["zip","path-traversal","zip-slip","security","skill"],"backgroundTag":"archive-path-traversal","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}