langflow-ai/langflow · warning · HTTPException

Invalid fs_path: null bytes are not allowed

Error message

Invalid fs_path: null bytes are not allowed

What it means

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.

Source

Thrown at src/backend/base/langflow/api/v1/flows_helpers.py:71

    Uses ``os.path.realpath`` + ``startswith`` for containment — the sanitiser pattern
    recognised by CodeQL's ``py/path-injection`` analysis. ``realpath`` canonicalises
    the path and follows symlinks, so the returned path is safe to pass to filesystem
    operations.
    """
    if not fs_path:
        raise HTTPException(status_code=400, detail="fs_path cannot be empty")

    # Normalize path separators first (before security checks to prevent backslash bypass)
    normalized_path = fs_path.replace("\\", "/")

    # Reject directory traversal and null bytes (check normalized path)
    if ".." in normalized_path:
        raise HTTPException(
            status_code=400,
            detail="Invalid fs_path: directory traversal (..) is not allowed",
        )
    if "\x00" in normalized_path:
        raise HTTPException(
            status_code=400,
            detail="Invalid fs_path: null bytes are not allowed",
        )

    # Build and canonicalise the safe base directory path.
    base_dir = storage_service.data_dir / "flows" / str(user_id)
    try:
        base_dir_resolved = os.path.realpath(str(base_dir))
    except (OSError, ValueError) as e:
        raise HTTPException(status_code=400, detail=f"Invalid base directory: {e}") from e

    # Determine if path is absolute (Unix or Windows style)
    is_absolute = normalized_path.startswith("/") or (len(normalized_path) > 1 and normalized_path[1] == ":")

    if is_absolute:
        candidate = normalized_path
    else:
        relative_part = normalized_path.lstrip("/")

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Strip control characters from fs_path before sending: fs_path.replace(/\x00/g, '').
  2. Verify the field you are putting into fs_path actually holds a path and not raw data from another field.
  3. If a fuzzer produced it, no action needed — the guard worked as intended.

Example fix

# before
{"fs_path": "flow\u0000.json"}
# after
{"fs_path": "flow.json"}
Defensive patterns

Strategy: validation

Validate before calling

if (/\x00/.test(fsPath)) throw new Error('fs_path must not contain NUL bytes');

Type guard

const isCleanPath = (p: string) => !/[\x00-\x1f]/.test(p);

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/2701fc9325facf86. Report an issue: GitHub.