The Validator Executed What It Was Checking: Langflow CVE-2026-51886 and the Decorator That Ran at Definition Time

On 5 October 2026 at 22:31 UTC, GitHub published GHSA-w584-2h2r-2hvf for CVE-2026-51886: an authenticated remote code execution flaw in Langflow’s code validator, rated CVSS 3.1 8.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, CWE-94 code injection), affecting versions ≥ 1.7.2 and < 1.10.1, fixed in 1.10.1. The mechanism is a Python-semantics classic that keeps catching validators: POST /api/v1/validate/code compiled and exec()’d every function definition in the submitted code as part of “validation” — and executing a def statement evaluates its decorators and default-argument expressions at definition time. A payload like def f(x=__import__("os").system("...")): ... runs arbitrary code during validation without the function ever being called.

This is the same endpoint family that produced January’s CVE-2026-0768 — the unauthenticated /validate exec that ZDI disclosed as a zero-day and that is still generating victims nine months later. The sink moved behind authentication in v1.7.2 (commit 3fed9fe1b5, PR #10977), but the exec() itself survived untouched from 1.7.2 through 1.10.0, and the advisory is explicit that under the default AUTO_LOGIN single-user setup the flaw is effectively unauthenticated. January closed the open door; October closes the quirk in what the validator was allowed to do once inside. And it lands in a week when Langflow is already having a bad one — the duplicate 9.9 MCP-stdio pair and the 25-flaw batch fixed in 1.12.3.

What the code did, and what the fix removed

The sink lived in validate_code in src/lfx/src/lfx/custom/validate.py, exposed through src/backend/base/langflow/api/v1/validate.py. For each ast.FunctionDef node it compiled the node and ran exec(code_obj, exec_globals), where exec_globals came from a _create_langflow_execution_context() helper that the advisory describes as restricted-looking but with standard builtins available. The threat model assumed that defining a function is inert. In CPython it is not: decorators execute, default expressions execute, and the “validation” phase becomes an execution phase with the caller’s code.

The fix (PR #13696, commit e7c33dba, reported by ESPanda666 and l3tchupkt with a duplicate report folded in) does the obvious correct thing: validate_code now compiles each function only, to surface syntax errors, and never exec()s it. The now-dead _create_langflow_execution_context helper was deleted along with its isolation tests, and a regression test — test_validate_code_does_not_execute_default_args — submits a function whose default argument would create a file as a side effect and asserts the file never appears. The legitimate component-execution paths (create_function, execute_function, eval_function), separately gated by allow_custom_components, are unchanged. Net diff: 32 additions, 113 deletions, almost all of them deletion. The best validator patch is the one that removes the interpreter from the validation path.

What to do

  • Upgrade to Langflow 1.10.1 or later. Anything from 1.7.2 through 1.10.0 carries the sink; current releases (including the 1.12.3 batch) include the compile-only fix.
  • Do not rely on AUTO_LOGIN=false as the fix. Authentication narrows this to an insider-or-credential threat, but multi-user Langflow deployments hand sessions to people who should never get server code execution. Patch the sink, not just the gate.
  • Audit the validator’s other expressions. The fix covers function definitions; any adjacent path that still exec()s or eval()s submitted AST — class bodies, for instance, execute at definition time too — deserves the same compile-only treatment.
  • If you ran a vulnerable version exposed to untrusted users, assume evaluation happened. A gist proof of concept is referenced in the advisory, and the January precedent on this endpoint family shows exploitation tooling arrives fast and persists for months.

Verification note: CVE number, GHSA identifier, publication timestamp, CVSS vector and score, CWE, affected range, patched version, sink file paths, endpoint, exec-semantics mechanism, pre-1.7.2 unauthenticated history, AUTO_LOGIN consequence, reporters, issue/PR/commit references and the gist PoC pointer come from the GitHub global advisory API record for GHSA-w584-2h2r-2hvf (reviewed, 10 comments). Fix behavior, payload shape, helper removal, regression-test design and the create/execute/eval_function scoping come from the fix commit e7c33dba and its file patches, read via the GitHub REST API. We ran no exploit and tested no deployment before publication.

Sources: