FlawOpen

flawopen.com/Teardowns/cve-2026-105697-langflow-mcp-stdio-command-injection

● CVE-2026-105697 · CVSS 9.9[1] · 緊急
セキュリティ研究 · FlawOpen

CVE-2026-105697:Langflow MCP コマンドインジェクション

1.10.3 より前の Langflow は、MCP stdio 設定をシェル経由で起動するプロセスに渡していました。ネットワークから到達可能で LANGFLOW_AUTO_LOGIN=true のインスタンスでは、攻撃者は認証情報なしでトークンを取得できました。自動ログインを無効にしても、認証済みの非管理者ユーザーはこの脆弱性を悪用してホスト上でコマンドを実行できます。1.10.3 では全経路と起動直前に検証し、シェルを介さず起動します。[1], [2], [3]

CVSS ベクトルCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H[1]
💡 わかりやすい解説 (ELI5)

句読点によって仕事の内容が変わる文を受け取る係員を想像してください。ある記号が配送指示を別の命令に変えてしまうことがあります。Langflow は設定されたコマンドをシェルに渡し、実行ファイルと引数を別々のデータとして扱わず、構文を制御指示として解釈させていました。修正では許可されたコマンドを検証し、シェルを介さずにプログラムを起動します。[1], [2]

主要な概念と専門用語

MCP stdio トランスポート
MCP サーバーをローカルの子プロセスとして起動し、標準入出力でプロトコルメッセージを交換します。[1], [2]
コマンドインジェクション(CWE-78)
外部から影響を受ける文字列が、シェルやプロセス起動処理へ渡す OS コマンドを変えてしまいます。[1], [5]
実行箇所
プロセスを生成する最終コード経路です。API で先に検査していても、ここで検証が必要です。[1], [2]
flow/tweak 埋め込み設定
設定 API ではなく、flow や実行時の上書きに含まれる MCP 設定です。[1], [2]

フレームワーク対応

  • このガイドで説明する弱点の CWE 参照: CWE-78

根本原因の分析 (Root Cause)

1.10.3 より前は、MCP stdio 設定でコマンドと引数を文字列にまとめ、bash -c で起動していました。1.9.0 では設定 API に許可リストと引数・環境の検査が追加されましたが、flow や tweak に埋め込まれた MCP Tools 設定は、実行箇所に共通ポリシーがなかったためモデル検証を回避できました。Langflow 1.10.3 は lfx.base.mcp.security.validate_mcp_stdio_config に検証を集約し、API、flow、tweak、旧コンポーネント、起動直前のすべてで適用して、シェルを介さず起動します。CVE-2026-105697 は CWE-78、CVSS 3.1 で 9.9 です。自動ログインを無効にしていても、該当する MCP 経路を設定または実行できる認証済み非管理者ユーザーが必要です。既定の自動ログインは、公開された開発環境を認証なしで到達可能にする場合があります。[1], [2], [4], [5]

ステップ・バイ・ステップの攻撃フロー

ステップ 1

ユーザーが MCP 設定経路に到達

アドバイザリでは、MCP サーバー設定または MCP Tools コンポーネントを使う flow 経由のアクセスが説明されています。ネットワークから到達可能で開発用の既定値 LANGFLOW_AUTO_LOGIN=true のインスタンスでは、認証情報なしでトークンを取得できました。自動ログインを無効にしても、認証済みの非管理者ユーザーで成立する場合があります。[1]

ステップ 2

設定がプロセス準備へ進む

MCP stdio 接続の準備中に、コマンドと引数が command_str になります。[1]

ステップ 3

シェルが文字列を解釈

1.10.3 より前の起動経路は bash -c を使用し、MCP handshake 成功前の接続試行時に実行されます。[1]

ステップ 4

入口検査が不十分

1.9.0 は REST 設定を検証しますが、flow や tweak の設定はモデル検証を迂回できます。[1]

ステップ 5

ホストプロセスは Langflow の権限で動作

コマンドは Langflow サービスのユーザーとして実行されます。画面上では MCP サーバーの起動失敗と表示される場合があります。[1]

ステップ 6

1.10.3 が実行境界を閉じる

共通ポリシーが各入口とプロセス起動直前に設定を検証し、シェルを介さずプログラムを起動します。[1], [2]

ソースコード比較:脆弱 vs 堅牢化

脆弱な抜粋はアドバイザリに記載された shell 経由の起動方法を示すもので、実行可能な exploit ではありません。修正後の抜粋は 1.10.3 の設計を要約しています。共通ポリシーが各入口とプロセス生成直前に設定を検証し、API は実行ファイルと引数を分けて渡します。直接起動により shell の解釈はなくなりますが、許可された実行ファイルやパッケージがすべて安全になるわけではありません。運用環境に応じたパッケージソース制限と隔離も必要です。[1], [2]

ソース抜粋: lfx/base/mcp/util.py — 該当箇所の抜粋

脆弱な実装
# アドバイザリに記載された影響を受ける起動形式(抜粋):
server_params = StdioServerParameters(
    command="bash",
    args=["-c", f"exec {command_str}"],
    env=env_data,
)
堅牢化されたセキュアパッチ
# 1.10.3 のソースに基づく簡略例: ポリシーを検証してから直接プロセスを起動する。
command_parts = shlex.split(command_str)
if not command_parts:
    raise ValueError("MCP stdio command is required")
command, args = command_parts[0], command_parts[1:]
validate_mcp_stdio_config(command, args, env_data)  # Repeat at the execution boundary.
server_params = StdioServerParameters(
    command=command,
    args=args,
    env=env_data,
)  # No shell wrapper. The shared validator rejects disallowed configurations.

エンジニアリング&システム堅牢化チェックリスト

参考資料