{"record":{"id":"a8f9382993bd3b08","repo":"langflow-ai/langflow","slug":"invalid-flow-filename-flow-filename","errorCode":null,"errorMessage":"Invalid flow filename: '{flow_filename}'","messagePattern":"Invalid flow filename: '(.+?)'","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"src/backend/base/langflow/agentic/services/helpers/flow_loader.py","lineNumber":73,"sourceCode":"\ndef resolve_flow_path(flow_filename: str) -> tuple[Path, str]:\n    \"\"\"Resolve flow filename to path and determine type.\n\n    Supports both explicit extensions (.json, .py) and auto-detection.\n    Priority: explicit extension > .py > .json\n\n    Args:\n        flow_filename: Name of the flow file (with or without extension).\n\n    Returns:\n        tuple[Path, str]: (resolved path, file type: \"json\" or \"python\")\n\n    Raises:\n        HTTPException: If flow file not found.\n    \"\"\"\n    # Early rejection of path traversal sequences before any path construction.\n    if \"..\" in flow_filename or \"\\\\\" in flow_filename:\n        raise HTTPException(status_code=400, detail=f\"Invalid flow filename: '{flow_filename}'\")\n\n    if flow_filename.endswith(\".json\"):\n        flow_path = _safe_resolved_path(FLOWS_BASE_PATH / flow_filename)\n        if flow_path.exists():\n            return flow_path, \"json\"\n        raise HTTPException(status_code=404, detail=f\"Flow file '{flow_filename}' not found\")\n\n    if flow_filename.endswith(\".py\"):\n        flow_path = _safe_resolved_path(FLOWS_BASE_PATH / flow_filename)\n        if flow_path.exists():\n            return flow_path, \"python\"\n        raise HTTPException(status_code=404, detail=f\"Flow file '{flow_filename}' not found\")\n\n    # Auto-detect: try Python first, then JSON (allows gradual migration)\n    base_name = flow_filename.rsplit(\".\", 1)[0] if \".\" in flow_filename else flow_filename\n\n    py_path = _safe_resolved_path(FLOWS_BASE_PATH / f\"{base_name}.py\")\n    if py_path.exists():","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/agentic/services/helpers/flow_loader.py#L55-L91","documentation":"First-line defense in resolve_flow_path: any flow_filename containing '..' or a backslash is rejected with HTTP 400 before any path is constructed. It complements the realpath-based check in _safe_resolved_path, catching obvious traversal payloads early (including Windows-style separators) so they never reach filesystem APIs.","triggerScenarios":"GET/POST to an agentic execute endpoint with flow_name such as '../app/flows/x.json', 'a\\b.json', or '..%2F..%2Fetc%2Fpasswd' after URL decoding; the substring check fires regardless of whether the path would actually escape.","commonSituations":"Attackers probing for traversal; clients accidentally passing OS paths ('C:\\flows\\x.json' or 'flows/../flows/x.json'); filenames copied from error messages that include relative prefixes.","solutions":["Send only the bare file name relative to the flows directory (e.g. 'assistant.json').","Sanitize client-side: reject strings containing '..', '\\\\', or '/' where subdirectories are not intended.","If you administer the server, treat repeated 400s of this shape as probing and monitor them."],"exampleFix":"# before\nname = '../../shared/assistant.json'\n# after\nname = 'assistant.json'  # must live directly under FLOWS_BASE_PATH","handlingStrategy":"validation","validationCode":"const clean = (name) => {\n  if (/[.]{2}|\\\\|\\//.test(name)) throw new Error(`unsafe flow name: ${name}`);\n  return name;\n};","typeGuard":"const hasNoTraversal = (n: string): boolean => !n.includes('..') && !n.includes('\\\\');","tryCatchPattern":"Reject client-side before the request; if the server still returns 400 'Invalid flow filename', treat the input path as hostile and halt.","preventionTips":["Encode flow_name with encodeURIComponent and validate the decoded form against a whitelist regex.","Strip directory components: use only Path(name).name / basename.","Monitor 400s of this shape — they indicate probing."],"tags":["agentic","path-traversal","security","http-400","flow-loader"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}