langflow-ai/langflow · error · HTTPException

Invalid filename

Error message

Invalid filename

What it means

validate_public_files() rejects a file reference whose basename is exactly '.' after the path already passed the format and namespace checks. It is part of the hardening for GHSA-rcjh-r59h-gq37, which restricted unauthenticated public-flow builds to file paths of the form {source_flow_id}/{basename}. Although the '..' substring is already rejected earlier, a lone '.' basename (the current directory) is blocked here as an extra guard so anonymous callers cannot address the flow's directory itself.

Source

Thrown at src/backend/base/langflow/api/utils/flow_utils.py:171

    Called from any endpoint that accepts caller-supplied file references
    under a public-access boundary.
    """
    if not files:
        return
    expected_flow_id = str(source_flow_id).lower()
    for entry in files:
        if not isinstance(entry, str) or not entry:
            raise HTTPException(status_code=400, detail="Invalid file entry")
        if any(token in entry for token in _PUBLIC_FILE_REJECTED_SUBSTRINGS):
            raise HTTPException(status_code=400, detail="Invalid file path")
        match = _PUBLIC_FILE_PATH_RE.match(entry)
        if not match:
            raise HTTPException(status_code=400, detail="Invalid file path format")
        flow_id_segment, basename = match.group(1), match.group(2)
        if flow_id_segment.lower() != expected_flow_id:
            raise HTTPException(status_code=400, detail="File not in this flow's namespace")
        if basename in (".", ".."):
            raise HTTPException(status_code=400, detail="Invalid filename")


def compute_virtual_flow_id(
    identifier: str | uuid.UUID,
    flow_id: uuid.UUID,
    *,
    principal_type: Literal["user", "client"] | None = None,
) -> uuid.UUID:
    """Compute a deterministic virtual flow ID for session/message isolation.

    Args:
        identifier: A unique identifier (user_id for authenticated users, client_id for anonymous).
        flow_id: The original flow ID.
        principal_type: Optional identity domain for public-flow callers. Authenticated
            user IDs and anonymous client IDs must never share a UUID namespace.

    Returns:
        A deterministic UUID v5 derived from the identifier and flow_id.

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Fix the client to send only plain basenames under the flow's own UUID, e.g. '{flow_id}/report.pdf' — never '.' or '..'.
  2. If you construct paths programmatically, split on '/' and drop empty components instead of using normpath before sending to the API.
  3. If you legitimately need directory-like grouping, upload under a flattened name (e.g. 'folder_report.pdf'); the API only accepts a single path segment.
  4. If you operate the server and see floods of these, treat them as probes of GHSA-rcjh-r59h-gq37 and rate-limit the endpoint.

Example fix

# before
files = [f"{flow_id}/{os.path.normpath(rel_path)}"]  # normpath('....') can yield '.'

# after
rel = rel_path.strip('/').split('/')[-1]  # keep basename only
if rel in ('.', '..'):
    raise ValueError(f"bad file path: {rel_path}")
files = [f"{flow_id}/{rel}"]
Defensive patterns

Strategy: validation

Validate before calling

import re
PATH_RE = re.compile(r'^([0-9a-fA-F-]{36})/([^/\\]+)$')

def safe_public_files(files, flow_id):
    fid = str(flow_id).lower()
    out = []
    for f in files or []:
        m = PATH_RE.match(f)
        if (not m or m.group(1).lower() != fid or m.group(2) in ('.', '..')
                or any(t in f for t in ('..', '\\', '\x00'))):
            raise ValueError(f'unsafe file entry: {f!r}')
        out.append(f)
    return out

Try / catch

try:
    validate_public_files(files, flow_id)
except HTTPException as e:
    if e.status_code == 400 and e.detail == 'Invalid filename':
        # strip '.'/'..' entries client-side and rebuild the list
        ...
    raise

Prevention

When it happens

Trigger: A caller of a public-flow build/upload endpoint passes a files list entry like '3f0b.../.' (flow UUID matching the public flow, basename exactly '.'). Note that entries containing '..' anywhere, backslashes, NUL bytes, non-UUID prefixes, or a foreign flow UUID fail earlier with 'Invalid file path'/'Invalid file path format'/'File not in this flow's namespace' instead.

Common situations: Client code that builds file paths by string concatenation (os.path.join or f-strings) and accidentally appends an empty segment; scripts replaying captured upload requests after path normalization (os.path.normpath turns './' into '.'); crafted probes against a shared public flow trying to escape the {flow_id}/ namespace.

Related errors


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