{"record":{"id":"be0179effbb4610d","repo":"unslothai/unsloth","slug":"dataset-path-may-not-contain-null-bytes","errorCode":null,"errorMessage":"dataset path may not contain null bytes","messagePattern":"dataset path may not contain null bytes","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"studio/backend/hub/utils/paths.py","lineNumber":393,"sourceCode":"    \"\"\"True when *path* is *root* or lives beneath it.\n\n    Compares real (symlink-resolved, case-normalized) paths so the check holds\n    through symlinks and on case-insensitive filesystems, where a plain\n    ``Path.is_relative_to`` would miss a casing-only match. Returns False on any\n    resolution error rather than raising.\n    \"\"\"\n    try:\n        path_real = os.path.normcase(os.path.realpath(str(path)))\n        root_real = os.path.normcase(os.path.realpath(str(root)))\n        return os.path.commonpath([path_real, root_real]) == root_real\n    except (OSError, ValueError):\n        return False\n\n\ndef resolve_dataset_path(path_value: str) -> Path:\n    raw = str(path_value or \"\").strip()\n    if \"\\x00\" in raw:\n        raise ValueError(\"dataset path may not contain null bytes\")\n    # Normalize first so Windows/UNC and backslash paths resolve like the rest of the Hub path\n    # layer, and a backslashed '..' is caught by the traversal guard below.\n    normalized = normalize_path(raw)\n    path = Path(normalized).expanduser()\n    if \"..\" in path.parts:\n        raise ValueError(f\"dataset path may not contain '..' segments: {raw!r}\")\n    if path.is_absolute():\n        for root in (datasets_root(), dataset_uploads_root(), recipe_datasets_root()):\n            try:\n                _assert_contained(path, root)\n                return path\n            except ValueError:\n                continue\n        raise ValueError(f\"dataset path must be relative or under a dataset root: {raw!r}\")\n\n    parts = [part for part in Path(normalized).parts if part not in (\"\", \".\")]\n    if parts[:2] == [\"assets\", \"datasets\"]:\n        parts = parts[2:]","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/hub/utils/paths.py#L375-L411","documentation":"First guard in resolve_dataset_path: the raw path string contains a NUL byte (\\x00). NUL cannot appear in real filesystem paths and would otherwise be smuggled into OS syscalls where it truncates or corrupts the path — a classic path-traversal/injection vector. It is rejected before any normalization.","triggerScenarios":"Calling any dataset path API with a value containing \\x00, e.g. 'data/\\x00/../../etc' or a binary-mangled payload from a client that concatenates C strings.","commonSituations":"Fuzzing or malformed multipart/upload payloads; values decoded from a broken encoding; C-extension or shell glue that passes NUL-terminated buffers into Python.","solutions":["Strip/reject NUL bytes client-side before sending the path.","Fix the producer of the string (encoding bug, buffer concatenation) — a NUL in a path is always a bug upstream.","Server-side, catch ValueError and return 400 rather than letting it become a 500."],"exampleFix":"// before\nbody = { path: rawBuffer.toString('utf8') }  // may contain \\0\n// after\nconst p = rawBuffer.toString('utf8');\nif (p.includes('\\0')) throw new Error('invalid path');\nbody = { path: p };","handlingStrategy":"validation","validationCode":"def dataset_path_is_clean(path_value: str) -> bool:\n    raw = (path_value or \"\").strip()\n    return bool(raw) and \"\\x00\" not in raw","typeGuard":null,"tryCatchPattern":"try:\n    p = resolve_dataset_path(value)\nexcept ValueError as e:\n    if \"null bytes\" in str(e):\n        return bad_request(\"path contains invalid characters\")  # 400, not 500","preventionTips":["Reject NUL bytes in path inputs at the API boundary (before any storage or OS call).","Fix upstream producers that concatenate binary buffers into path strings.","Treat NUL-in-path as a client bug or attack, never as a normal user error."],"tags":["validation","security","path-traversal","datasets"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}