{"record":{"id":"6b89e2e6e39bcbda","repo":"t8y2/dbx","slug":"truncated-pe-import-descriptor","errorCode":null,"errorMessage":"truncated PE import descriptor","messagePattern":"truncated PE import descriptor","errorType":"exception","errorClass":"PeFormatError","httpStatus":null,"severity":"error","filePath":"agents/scripts/validate_windows_pe_dependencies.py","lineNumber":91,"sourceCode":"        )\n\n    def rva_to_offset(rva: int) -> int:\n        if rva < size_of_headers:\n            return rva\n        for virtual_address, virtual_size, raw_offset, raw_size in sections:\n            span = max(virtual_size, raw_size)\n            if virtual_address <= rva < virtual_address + span:\n                delta = rva - virtual_address\n                if delta >= raw_size:\n                    break\n                return raw_offset + delta\n        raise PeFormatError(f\"PE RVA 0x{rva:x} is not backed by file data\")\n\n    descriptor_offset = rva_to_offset(import_directory_rva)\n    imports = []\n    for _ in range(4096):\n        if descriptor_offset + 20 > len(data):\n            raise PeFormatError(\"truncated PE import descriptor\")\n        descriptor = data[descriptor_offset : descriptor_offset + 20]\n        if descriptor == b\"\\0\" * 20:\n            return sorted(set(imports), key=str.casefold)\n        name_rva = _read_u32(data, descriptor_offset + 12)\n        if name_rva == 0:\n            raise PeFormatError(\"PE import descriptor has no DLL name\")\n        imports.append(_read_c_string(data, rva_to_offset(name_rva)))\n        descriptor_offset += 20\n\n    raise PeFormatError(\"PE import descriptor table is not terminated\")\n\n\ndef forbidden_msvc_runtime_dlls(imports: list[str]) -> list[str]:\n    return sorted(\n        {name for name in imports if name.casefold().startswith((\"msvcp\", \"vcruntime\"))},\n        key=str.casefold,\n    )\n","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/scripts/validate_windows_pe_dependencies.py#L73-L109","documentation":"Each IMAGE_IMPORT_DESCRIPTOR is a 20-byte structure walked sequentially from the import directory. This error is raised when fewer than 20 bytes remain in the file at the current descriptor offset, i.e. the import descriptor array runs off the end of the file before the terminating all-zero descriptor is found. It indicates a truncated or corrupt import table rather than a legitimate terminator.","triggerScenarios":"imported_dlls(path) on a PE where descriptor_offset + 20 exceeds len(data) during the descriptor walk — e.g. the import directory RVA resolves near end-of-file, the file was truncated, or the import directory size field disagrees with the actual descriptor array.","commonSituations":"Incomplete download or failed copy of the binary; a build artifact sliced by packaging tooling; fuzzed/malicious PE samples with truncated sections; disk corruption on build machines.","solutions":["Re-download or rebuild the binary and compare its size/hash against the original artifact; truncation is the usual cause.","Validate the import directory RVA/size against the section bounds with pefile before running the script.","Wrap the call in try/except PeFormatError and report the binary as malformed instead of aborting the whole validation batch.","If you produce the binaries, check that your linker/packager emits a complete, zero-terminated import descriptor table."],"exampleFix":"// before\nimports = imported_dlls(Path(binary_path))\n// after\ntry:\n    imports = imported_dlls(Path(binary_path))\nexcept PeFormatError as err:\n    print(f\"rejecting {binary_path}: {err}\")\n    sys.exit(1)","handlingStrategy":"try-catch","validationCode":"import os\n\ndef file_size_at_least(path, min_bytes: int) -> bool:\n    return os.path.getsize(path) >= min_bytes\n# Also compare against expected build-artifact size/hash to catch truncation early.","typeGuard":null,"tryCatchPattern":"try:\n    imports = imported_dlls(path)\nexcept PeFormatError as err:\n    if \"truncated\" in str(err):\n        quarantine(path, reason=err)\n    else:\n        raise","preventionTips":["Verify downloads/copies with checksums to rule out truncation.","Don't process binaries mid-transfer or from partial build outputs.","Validate the import directory size (data dir index 1) is a multiple of 20 before parsing.","Run pefile.parse_data_directories as a pre-check in CI."],"tags":["pe-format","import-table","truncated-file","binary-parsing","python"],"backgroundTag":"truncated-pe-import-descriptor","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}