{"slug": "cve-2026-17633-authenticated-rce-in-langflow-oss-via-api-v1-custom-component", "title": "CVE-2026–17633 - Authenticated RCE in Langflow OSS via /api/v1/custom_component", "summary": "A security researcher detailed CVE-2026-17633, a high-severity authenticated remote code execution flaw in Langflow OSS versions 1.0.0 through 1.10.3, disclosed in an IBM security advisory published August 5, 2026. The vulnerability in the POST /api/v1/custom_component endpoint allows any authenticated user to execute arbitrary Python when custom components are enabled, because the endpoint's only gate checks whether the feature is turned on rather than inspecting code content, and its prepare_global_scope() function drops module-level expressions from the AST while executing statements placed inside a class body. The researcher noted the exploit requires no filter bypass, only placing the payload inside the class definition.", "body_md": "| Field | Value | \n|---|---|\n| CVE ID | CVE-2026-17633 | \n| CVSS | 8.5 (HIGH) | \n| CWE | CWE-94 (Improper Control of Generation of Code) | \n| Affected | Langflow OSS 1.0.0 – 1.10.3 | \n| Preconditions | Any authenticated user + `LANGFLOW_ALLOW_CUSTOM_COMPONENTS=true` | \n| Vulnerable endpoint | `POST /api/v1/custom_component` | \n\nLangflow is an open-source low-code platform for building LLM applications and agent workflows visually. One of its features, **Custom Components**, lets users define a component's behavior directly in Python. That feature is the attack surface for this vulnerability.\n\nIBM's security advisory (published August 5, 2026) disclosed a cluster of issues in Langflow OSS 1.0.0–1.10.3. CVE-2026–17633 is the authenticated RCE reachable through `/api/v1/custom_component`.\n\nFrom `langflow/api/v1/endpoints.py` (around line 1271):\n\n```\n@router.post(\"/custom_component\", status_code=HTTPStatus.OK, include_in_schema=False)\nasync def custom_component(\n raw_code: CustomComponentRequest,\n user: CurrentActiveUser,\n request: Request,\n) -> CustomComponentResponse:\n …\n # The only gate: \"is the custom-component feature enabled at all?\"\n if not settings.allow_custom_components and not code_hash_matches_any_template(raw_code.code, all_known):\n raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, …)\n# scan_code_security() is never called here\n component = Component(_code=effective_code)\n built_frontend_node, component_instance = build_custom_component_template(component, user_id=user.id)\n```\n\nThe important detail isn't that there's \"no validation\" - it's that the validation checks the wrong thing. `allow_custom_components` answers \"is this user allowed to create custom components,\" not \"is this code's content safe.\" In production, `LANGFLOW_ALLOW_CUSTOM_COMPONENTS=true` is a common setting, and once it's on, this check passes trivially and the code flows through with zero content inspection.\n\nLangflow does ship a separate AST-based scanner, `scan_code_security()` (covered in section 5), but this endpoint's execution path never calls it.\n\n`prepare_global_scope()`\n`custom_component()` calls `build_custom_component_template()`, which flows into `create_class()` in `lfx/custom/validate.py`. That function calls `prepare_global_scope()`, and the submitted code is `exec()`'d shortly after.\n\n``` python\ndef prepare_global_scope(module):\n exec_globals = globals().copy()\n …\n for node in module.body:\n if isinstance(node, ast.Import | ast.ImportFrom):\n imports.append(node)\n elif isinstance(node, ast.ClassDef | ast.FunctionDef | ast.Assign | ast.AnnAssign):\n definitions.append(node)\n …\n if definitions:\n compiled_code = compile(combined_module, \"<string>\", \"exec\")\n exec(compiled_code, exec_globals) # ← exec() happens here\n```\n\nThis function walks the submitted code's AST and only collects `import` statements and `class`/` def`/assignment nodes into `definitions`. That's the trap.\n\n`os.system(…)` is, at the AST level, an `ast.Expr` node.`isinstance` allow-list above → it's `ClassDef` node - so when the class is defined (i.e., when `exec()` runs), that code executes right along with it.\n\n```\n# ❌ Module level - classified as ast.Expr, silently dropped by prepare_global_scope()\nimport os\nos.system(\"id > /tmp/pwned.txt\")\nclass PocComponent(Component):\n …\n# ✅ Inside the class body - part of ClassDef, runs when exec() defines the class\nclass PocComponent(Component):\n os.system(\"id > /tmp/pwned.txt\") # ← executes at class-definition time\n …\n```\n\nSo the entire trick an attacker needs is: **put the payload inside the class body, not at module level.** No encoding tricks, no filter bypass gymnastics - just a simple, and simply devastating, design flaw.\n\nThe diagram below traces the full path from request to command execution.\n\nIn short:\n\n```\nAuthenticated user (any privilege level)\n │\n ▼\nPOST /api/v1/custom_component { \"code\": \"<malicious Python class>\" }\n │\n ▼\nbuild_custom_component_template() → create_class()\n │\n ▼\nprepare_global_scope() - only ClassDef nodes get collected into definitions/exec target\n │\n ▼\ncompile_class_code() → exec(compiled_class, exec_globals)\n │\n ▼\nClass body executes at definition time → RCE achieved\n```\n\nNo LLM involvement, no scanner to evade. One HTTP request is enough.\n\nLangflow ships a separate AST-based scanner, `scan_code_security()`, in `langflow/agentic/helpers/code_security.py`. But it's wired only into the **Agentic Assistant path** (validating LLM-generated component code) - it's never called from `/api/v1/custom_component` at all.\n\nSo CVE-2026–17633 isn't really a scanner bypass; it's exploiting a code path the scanner was never attached to in the first place. The scanner's own detection logic has a separate weakness (missing `vars()` coverage leading to a false `is_safe: True` verdict, tracked as CVE-2026–17632), which surfaced from analyzing the same codebase but is a distinct issue.\n\n`custom_component` endpoint`LANGFLOW_ALLOW_CUSTOM_COMPONENTS` set to `false` in production unless the feature is genuinely needed`gid=0` membership) to reduce lateral-movement / container-escape surface", "url": "https://wpnews.pro/news/cve-2026-17633-authenticated-rce-in-langflow-oss-via-api-v1-custom-component", "canonical_source": "https://dev.to/guidance_white/cve-2026-17633-authenticated-rce-in-langflow-oss-via-apiv1customcomponent-5baj", "published_at": "2026-09-21 23:06:07+00:00", "updated_at": "2026-09-21 23:24:23.000200+00:00", "lang": "en", "topics": ["ai-safety", "ai-products", "ai-agents", "developer-tools"], "entities": ["Langflow", "IBM", "CVE-2026-17633"], "alternates": {"html": "https://wpnews.pro/news/cve-2026-17633-authenticated-rce-in-langflow-oss-via-api-v1-custom-component", "markdown": "https://wpnews.pro/news/cve-2026-17633-authenticated-rce-in-langflow-oss-via-api-v1-custom-component.md", "text": "https://wpnews.pro/news/cve-2026-17633-authenticated-rce-in-langflow-oss-via-api-v1-custom-component.txt", "jsonld": "https://wpnews.pro/news/cve-2026-17633-authenticated-rce-in-langflow-oss-via-api-v1-custom-component.jsonld"}}