{"record":{"id":"e81cf830545d0746","repo":"ComposioHQ/composio","slug":"refusing-to-write-label-containing-a-nul-byte","errorCode":null,"errorMessage":"Refusing to write {label} containing a NUL byte: {name!r}","messagePattern":"Refusing to write (.+?) containing a NUL byte: (.+?)","errorType":"exception","errorClass":"UnsafePathComponentError","httpStatus":null,"severity":"critical","filePath":"python/composio/utils/safe_path.py","lineNumber":177,"sourceCode":"    both basename to ``\"\"``, which makes an output path equal to its own\n    directory and surfaces as ``IsADirectoryError`` at write time.\n\n    :raises UnsafePathComponentError: when ``name`` yields no usable basename or\n        is unsafe to write.\n    \"\"\"\n    if not isinstance(name, str):\n        raise UnsafePathComponentError(\n            f\"Refusing to write a non-string {label}: {name!r}\"\n        )\n\n    raw_basename = PureWindowsPath(name).name\n    if not raw_basename or not raw_basename.strip() or set(raw_basename) == {\".\"}:\n        raise UnsafePathComponentError(\n            f\"Path traversal detected: {label} {name!r} leaves no usable \"\n            \"basename to write to.\"\n        )\n    if \"\\x00\" in raw_basename:\n        raise UnsafePathComponentError(\n            f\"Refusing to write {label} containing a NUL byte: {name!r}\"\n        )\n    if any(ord(char) < 32 or char in '<>:\"|?*' for char in raw_basename):\n        raise UnsafePathComponentError(\n            f\"Refusing to write {label} containing characters reserved by \"\n            f\"Windows: {name!r}\"\n        )\n    if raw_basename.endswith((\" \", \".\")):\n        raise UnsafePathComponentError(\n            f\"Refusing to write {label} ending in a space or dot: {name!r}\"\n        )\n\n    basename = raw_basename.strip()\n    try:\n        encoded_length = len(os.fsencode(basename))\n    except UnicodeEncodeError as e:\n        raise UnsafePathComponentError(\n            f\"Refusing to write {label} containing invalid Unicode: {name!r}\"","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/utils/safe_path.py#L159-L195","documentation":"safe_basename rejects filenames containing a NUL byte (\\x00). NUL cannot appear in a filesystem path on Linux or Windows and would truncate/error at open() time; it is also a classic path-injection marker.","triggerScenarios":"secure_basename_join(base, name) where name (or its extracted basename) contains '\\x00' — e.g. 'file.txt\\x00.jpg' trying to exploit NUL truncation in C-based syscalls.","commonSituations":"Adversarial filenames from untrusted API responses; binary garbage decoded into strings.","solutions":["Strip or reject NUL-containing strings before filename handling","Treat a NUL byte in any path-ish field as malicious input and drop the whole request"],"exampleFix":"# before\nsecure_basename_join(base, name)\n# after\nif \"\\x00\" in name:\n    raise ValueError(\"invalid filename\")\nsecure_basename_join(base, name)","handlingStrategy":"validation","validationCode":"def nul_free(v):\n    return isinstance(v, str) and '\\x00' not in v","typeGuard":"def is_nul_free(v: str) -> bool:\n    return '\\x00' not in v","tryCatchPattern":"from composio.exceptions import UnsafePathComponentError\ntry:\n    p = secure_basename_join(base, name)\nexcept UnsafePathComponentError:\n    raise ValueError(f'malicious filename received: {name!r}')","preventionTips":["Reject the entire request when a filename contains NUL","Scan untrusted strings for control characters at ingest"],"tags":["nul-byte","path-validation","python","security"],"backgroundTag":"nul-byte-in-filename","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}