{"record":{"id":"a2177424d3745184","repo":"langflow-ai/langflow","slug":"absolute-path-must-be-within-your-flows-directory","errorCode":null,"errorMessage":"Absolute path must be within your flows directory","messagePattern":"Absolute path must be within your flows directory","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"src/backend/base/langflow/api/v1/flows_helpers.py","lineNumber":101,"sourceCode":"    # 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(\"/\")\n        # os.path.join is deliberate here (PTH118) to match CodeQL's sanitiser model.\n        candidate = os.path.join(base_dir_resolved, relative_part) if relative_part else base_dir_resolved  # noqa: PTH118\n\n    try:\n        resolved_str = os.path.realpath(candidate)\n    except (OSError, ValueError) as e:\n        raise HTTPException(status_code=400, detail=f\"Invalid path: {e}\") from e\n\n    # SECURITY: containment check using os.path.realpath + startswith (CodeQL-recognised).\n    if resolved_str != base_dir_resolved and not resolved_str.startswith(base_dir_resolved + os.sep):\n        if is_absolute:\n            raise HTTPException(\n                status_code=400,\n                detail=\"Absolute path must be within your flows directory\",\n            )\n        raise HTTPException(\n            status_code=400,\n            detail=\"Invalid path: resolves outside allowed directory\",\n        )\n\n    # Return the canonicalised path — safe for subsequent filesystem operations.\n    return Path(resolved_str)\n\n\n# Fields that may be updated via setattr on a Flow ORM instance.\n# Any key not in this set is silently dropped to prevent callers from\n# overwriting internal fields (e.g. ``id``, ``user_id``).\n_UPDATABLE_FLOW_FIELDS: frozenset[str] = frozenset(\n    {\n        \"name\",","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/flows_helpers.py#L83-L119","documentation":"HTTP 400: the submitted fs_path was absolute (starts with '/' or a Windows drive letter like 'C:') and, after realpath canonicalisation, does not lie inside <data_dir>/flows/<user_id>. The containment check (realpath + startswith with os.sep) is the CodeQL-recognised sanitiser; absolute paths are permitted only if they resolve inside the user's own flows directory.","triggerScenarios":"POST/PATCH /api/v1/flows with fs_path=\"/etc/passwd\", \"C:\\\\Users\\\\me\\\\flow.json\", or any absolute path outside data_dir/flows/<user_id>; also an absolute path that IS inside the dir textually but escapes via a symlink.","commonSituations":"Client migrates flows from an old instance that stored absolute paths and resubmits them verbatim on a new host; users pasting a local filesystem path into an fs_path field; pen-test probing for arbitrary file write.","solutions":["Send a relative fs_path (\"my_flow.json\"); it is automatically anchored under your flows directory.","If absolute is required, it must resolve inside <data_dir>/flows/<your user id>/.","When importing legacy flows, strip the old absolute prefix and keep just the basename."],"exampleFix":"# before\n{\"fs_path\": \"/home/olduser/langflow/flows/my_flow.json\"}\n# after\n{\"fs_path\": \"my_flow.json\"}","handlingStrategy":"validation","validationCode":"if (/^(\\/|[A-Za-z]:)/.test(fsPath)) throw new Error('send relative fs_path only');","typeGuard":"const isRelativeFsPath = (p: string) => !p.startsWith('/') && !/^[A-Za-z]:/.test(p.replace(/\\\\/g,'/'));","tryCatchPattern":null,"preventionTips":["Always send relative paths; the server anchors them","Strip legacy absolute prefixes during imports","Never paste local filesystem paths into fs_path"],"tags":["security","path-containment","validation","http-400","fs-path"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}