{"record":{"id":"cc43fbd006ff00e3","repo":"unslothai/unsloth","slug":"the-pinned-spec-name-archive-contains-a-non-regu","errorCode":null,"errorMessage":"The pinned {spec.name} archive contains a non-regular file","messagePattern":"The pinned (.+?) archive contains a non-regular file","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"studio/backend/utils/third_party_source.py","lineNumber":657,"sourceCode":"        member_count = 0\n        uncompressed_bytes = 0\n        extracted = set()\n        try:\n            with archive.open(\"rb\") as compressed:\n                with gzip.GzipFile(fileobj = compressed, mode = \"rb\") as decompressed:\n                    reader = _BoundedArchiveReader(decompressed, _ARCHIVE_MAX_TAR_BYTES)\n                    with tarfile.open(fileobj = reader, mode = \"r|\") as bundle:\n                        for member in bundle:\n                            member_count += 1\n                            if member_count > _ARCHIVE_MAX_MEMBERS:\n                                raise RuntimeError(\n                                    f\"The pinned {spec.name} archive has too many entries\"\n                                )\n                            parts = _archive_member_parts(member, spec)\n                            if member.isdir():\n                                continue\n                            if not member.isfile() or member.size < 0:\n                                raise RuntimeError(\n                                    f\"The pinned {spec.name} archive contains a non-regular file\"\n                                )\n                            uncompressed_bytes += member.size\n                            if uncompressed_bytes > _ARCHIVE_MAX_UNCOMPRESSED_BYTES:\n                                raise RuntimeError(\n                                    f\"The pinned {spec.name} archive expands too large\"\n                                )\n                            if len(parts) < 3 or parts[1] != spec.package:\n                                continue\n                            relative = \"/\".join(parts[1:])\n                            _package_path_parts(relative, spec, kind = \"archive\")\n                            if relative in extracted:\n                                raise RuntimeError(\n                                    f\"The pinned {spec.name} archive contains duplicate files\"\n                                )\n                            extracted.add(relative)\n                            source_file = bundle.extractfile(member)\n                            if source_file is None:","sourceCodeStart":639,"sourceCodeEnd":675,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/utils/third_party_source.py#L639-L675","documentation":"During member iteration, any entry that is neither a directory nor a regular file (symlink, device, fifo, hardlink) — or a regular file with a negative size — is rejected before extraction. Extraction code only ever calls open('wb') and copy loops, so irregular members must never reach it; this blocks symlink/hardlink attacks where a later file write would follow a link out of the staging tree.","triggerScenarios":"Archive contains a tar symlink entry (e.g. `pkg/lib -> /usr/lib`), a char/block device, a FIFO, or a member with size < 0 inside the target package subtree. Encountered when iterating a member that is not member.isdir() and fails member.isfile().","commonSituations":"Archives created on systems that preserve symlinks (many repos symlink docs/licenses); malicious archives planting symlinks to overwrite system files via later extraction; corrupt tar headers producing nonsense types/sizes.","solutions":["List entry types: tar -tvzf source.tar.gz | grep -v '^[-d]' to find symlinks/devices in the archive","Repack the source without symlinks (dereference with tar --dereference / cp -rL) and re-pin digests","Use the canonical codeload tarball for the revision — GitHub source archives do not contain device nodes; if they contain symlinks, this pin cannot be used and needs a sanitized mirror","If tampering is suspected (digest mismatch), treat as security incident"],"exampleFix":"# repack without symlinks, then re-pin\n# tar --dereference -czf clean.tar.gz foo-<sha>/\nPinnedSource(..., source_tree_digest=recompute_digest(clean_tree))","handlingStrategy":"validation","validationCode":"import tarfile\nwith tarfile.open(\"source.tar.gz\") as tf:\n    for m in tf:\n        if not (m.isdir() or m.isfile()) or m.size < 0:\n            raise SystemExit(f\"irregular member rejected: {m.name} type={m.type}\")","typeGuard":"def archive_members_regular(archive: Path) -> bool:\n    with tarfile.open(archive) as tf:\n        return all(m.isdir() or (m.isfile() and m.size >= 0) for m in tf)","tryCatchPattern":"try:\n    ensure_pinned_source(spec)\nexcept RuntimeError as e:\n    if \"non-regular file\" in str(e):\n        # repack with tar --dereference and re-pin digests","preventionTips":["Repack source trees with --dereference so no symlink entries reach the pin","Treat any irregular-member failure on a canonical artifact as tampering and verify digests out-of-band"],"tags":["security","tarfile","symlink","extraction","hardening"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}