{"record":{"id":"bd51014d997540bd","repo":"ComposioHQ/composio","slug":"path-traversal-detected-label-name-r-leaves-n","errorCode":null,"errorMessage":"Path traversal detected: {label} {name!r} leaves no usable basename to write to.","messagePattern":"Path traversal detected: (.+?) (.+?) leaves no usable basename to write to\\.","errorType":"validation","errorClass":"UnsafePathComponentError","httpStatus":null,"severity":"critical","filePath":"python/composio/utils/safe_path.py","lineNumber":172,"sourceCode":"    SDK runs on POSIX, where ``Path(...).name`` would return it intact.\n\n    Names that leave no usable basename are refused rather than replaced with a\n    generated one: a response that cannot name its own file is malformed or\n    hostile, and inventing a name would hide that. ``.`` and the empty string\n    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()","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/utils/safe_path.py#L154-L190","documentation":"safe_basename found no usable basename after taking PureWindowsPath(name).name — the value was empty, whitespace-only, all dots, or pure separators. Such a name would resolve to the base directory itself and surface as IsADirectoryError at write time, so it is treated as path traversal.","triggerScenarios":"secure_basename_join(base, ''), (base, '   '), (base, '...'), (base, '/'), (base, '..') — the basename extraction yields nothing writable.","commonSituations":"Empty filename fields from APIs; values that are entirely separator/dot characters crafted to escape to a parent or root.","solutions":["Fall back to a server-generated filename when extraction yields nothing","Reject the download/request carrying the empty name"],"exampleFix":"# before\nsecure_basename_join(base, fname)  # fname == '..'\n# after\nif not fname or set(fname) <= {'.', ' ', '/', '\\\\'}:\n    fname = f\"download-{uuid.uuid4().hex}\"\nsecure_basename_join(base, fname)","handlingStrategy":"validation","validationCode":"from pathlib import PureWindowsPath\ndef has_usable_basename(v):\n    b = PureWindowsPath(v).name if isinstance(v, str) else ''\n    return bool(b.strip()) and set(b) != {'.'}","typeGuard":"def is_writable_name(v: str) -> bool:\n    b = PureWindowsPath(v).name\n    return bool(b) and bool(b.strip()) and set(b) != {'.'}","tryCatchPattern":"from composio.exceptions import UnsafePathComponentError\nfrom uuid import uuid4\ntry:\n    p = secure_basename_join(base, name)\nexcept UnsafePathComponentError:\n    p = secure_basename_join(base, f'file-{uuid4().hex}')","preventionTips":["Never accept empty/dot-only filenames; substitute a generated name","Treat separator-only names as traversal attempts"],"tags":["path-traversal","python","security"],"backgroundTag":"empty-basename-path-traversal","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}