{"record":{"id":"2701fc9325facf86","repo":"langflow-ai/langflow","slug":"invalid-fs-path-null-bytes-are-not-allowed","errorCode":null,"errorMessage":"Invalid fs_path: null bytes are not allowed","messagePattern":"Invalid fs_path: null bytes are not allowed","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"src/backend/base/langflow/api/v1/flows_helpers.py","lineNumber":71,"sourceCode":"    Uses ``os.path.realpath`` + ``startswith`` for containment — the sanitiser pattern\n    recognised by CodeQL's ``py/path-injection`` analysis. ``realpath`` canonicalises\n    the path and follows symlinks, so the returned path is safe to pass to filesystem\n    operations.\n    \"\"\"\n    if not fs_path:\n        raise HTTPException(status_code=400, detail=\"fs_path cannot be empty\")\n\n    # Normalize path separators first (before security checks to prevent backslash bypass)\n    normalized_path = fs_path.replace(\"\\\\\", \"/\")\n\n    # Reject directory traversal and null bytes (check normalized path)\n    if \"..\" in normalized_path:\n        raise HTTPException(\n            status_code=400,\n            detail=\"Invalid fs_path: directory traversal (..) is not allowed\",\n        )\n    if \"\\x00\" in normalized_path:\n        raise HTTPException(\n            status_code=400,\n            detail=\"Invalid fs_path: null bytes are not allowed\",\n        )\n\n    # Build and canonicalise the safe base directory path.\n    base_dir = storage_service.data_dir / \"flows\" / str(user_id)\n    try:\n        base_dir_resolved = os.path.realpath(str(base_dir))\n    except (OSError, ValueError) as e:\n        raise HTTPException(status_code=400, detail=f\"Invalid base directory: {e}\") from e\n\n    # Determine if path is absolute (Unix or Windows style)\n    is_absolute = normalized_path.startswith(\"/\") or (len(normalized_path) > 1 and normalized_path[1] == \":\")\n\n    if is_absolute:\n        candidate = normalized_path\n    else:\n        relative_part = normalized_path.lstrip(\"/\")","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/flows_helpers.py#L53-L89","documentation":"HTTP 400: fs_path contained a NUL byte (\\x00). NUL bytes are rejected before path resolution because they can truncate/Corrupt paths at the OS layer and are a classic path-injection probe; the check is part of the same sanitiser chain as the traversal check in _get_safe_flow_path.","triggerScenarios":"Flow create/update with fs_path containing \"\\u0000\", e.g. \"a\\u0000.json\" — typically from unescaped binary data, a corrupted JSON payload, or a deliberately crafted request.","commonSituations":"Client serialises binary/garbage data into the fs_path field (encoding bug); security scanning/fuzzing tools probing the endpoint; copy-pasting a path that includes a control character.","solutions":["Strip control characters from fs_path before sending: fs_path.replace(/\\x00/g, '').","Verify the field you are putting into fs_path actually holds a path and not raw data from another field.","If a fuzzer produced it, no action needed — the guard worked as intended."],"exampleFix":"# before\n{\"fs_path\": \"flow\\u0000.json\"}\n# after\n{\"fs_path\": \"flow.json\"}","handlingStrategy":"validation","validationCode":"if (/\\x00/.test(fsPath)) throw new Error('fs_path must not contain NUL bytes');","typeGuard":"const isCleanPath = (p: string) => !/[\\x00-\\x1f]/.test(p);","tryCatchPattern":null,"preventionTips":["Strip control characters from all path-like fields client-side","Verify JSON encoding when paths originate from binary contexts"],"tags":["security","validation","null-byte","http-400","fs-path"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}