{"id":"PYSEC-2026-2570","summary":"Langflow: Authenticated Users Can Read, Modify, and Delete Any Flow via Missing Ownership Check","details":"## Vulnerability\n\n### IDOR in `GET/PATCH/DELETE /api/v1/flow/{flow_id}`\n\nThe `_read_flow` helper in `src/backend/base/langflow/api/v1/flows.py` branched on the `AUTO_LOGIN` setting to decide whether to filter by `user_id`. When `AUTO_LOGIN` was `False` (i.e., authentication was enabled), neither branch enforced an ownership check — the query returned any flow matching the given UUID regardless of who owned it.\n\nThis exposed any authenticated user to:\n\n- **Read** any other user's flow, including embedded plaintext API keys\n- **Modify** the logic of another user's AI agents\n- **Delete** flows belonging to other users\n\nThe vulnerability was introduced by the conditional logic that was meant to accommodate public/example flows (those with `user_id = NULL`) under auto-login mode, but inadvertently left the authenticated path without an ownership filter.\n\n---\n\n## Fix (PR #8956)\n\nThe fix removes the `AUTO_LOGIN` conditional entirely and unconditionally scopes the query to the requesting user:\n\n```diff\n-    auth_settings = settings_service.auth_settings\n-    stmt = select(Flow).where(Flow.id == flow_id)\n-    if auth_settings.AUTO_LOGIN:\n-        stmt = stmt.where(\n-            (Flow.user_id == user_id) | (Flow.user_id == None)  # noqa: E711\n-        )\n+    stmt = select(Flow).where(Flow.id == flow_id).where(Flow.user_id == user_id)\n```\n\nAll three operations — read, update, and delete — route through `_read_flow`, so the single change covers the full attack surface. A cross-user isolation test (`test_read_flows_user_isolation`) was added to prevent regression.\n\n---\n\n## Acknowledgements\n\nLangflow thanks the security researcher who responsibly disclosed this vulnerability:\n\n- **[@chximn-dt](https://github.com/chximn-dt)**","aliases":["CVE-2026-34046","GHSA-8c4j-f57c-35cf","PYSEC-2026-2567"],"modified":"2026-07-13T16:43:44.480752312Z","published":"2026-07-13T14:36:45.537461Z","references":[{"type":"WEB","url":"https://github.com/langflow-ai/langflow/security/advisories/GHSA-8c4j-f57c-35cf"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-34046"},{"type":"WEB","url":"https://github.com/langflow-ai/langflow/pull/8956"},{"type":"PACKAGE","url":"https://github.com/langflow-ai/langflow"},{"type":"PACKAGE","url":"https://pypi.org/project/langflow-base"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-8c4j-f57c-35cf"}],"affected":[{"package":{"name":"langflow-base","ecosystem":"PyPI","purl":"pkg:pypi/langflow-base"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.5.1"}]}],"versions":["0.0.13","0.0.14","0.0.15","0.0.16","0.0.17","0.0.18","0.0.19","0.0.20","0.0.21","0.0.22","0.0.23","0.0.24","0.0.25","0.0.26","0.0.27","0.0.28","0.0.29","0.0.30","0.0.31","0.0.32","0.0.33","0.0.34","0.0.35","0.0.36","0.0.37","0.0.38","0.0.39","0.0.40","0.0.41","0.0.42","0.0.43","0.0.44","0.0.45","0.0.46","0.0.47","0.0.48","0.0.49","0.0.50","0.0.51","0.0.52","0.0.53","0.0.54","0.0.55","0.0.56","0.0.57","0.0.58","0.0.59","0.0.60","0.0.61","0.0.62","0.0.63","0.0.64","0.0.66","0.0.67","0.0.68","0.0.69","0.0.70","0.0.71","0.0.72","0.0.73","0.0.74","0.0.75","0.0.76","0.0.77","0.0.78","0.0.79","0.0.80","0.0.81","0.0.82","0.0.83","0.0.84","0.0.85","0.0.86","0.0.87","0.0.88","0.0.89","0.0.90","0.0.91","0.0.92","0.0.93","0.0.94","0.0.95","0.0.96","0.0.97","0.0.98","0.0.99","0.1.0","0.1.1","0.1.2","0.1.3","0.1.4","0.1.4.post1","0.2.0","0.3.0","0.3.1","0.3.2","0.3.3","0.3.4","0.4.0","0.4.1","0.4.2","0.4.3","0.5.0","0.5.0.post1","0.5.0.post2"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/langflow-base/PYSEC-2026-2570.yaml"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"}]}