Langflow: MCP stdioサーバーの設定における任意のコマンドによるOSコマンドインジェクション(RCE)の脆弱性
### 概要
**Langflow 1.10.3**以前のバージョンでは、MCP stdioトランスポートが、ユーザーがMCPサーバーの設定に記述した任意の`command`(コマンド)/`args`(引数)を実行していました。この際、許可リストがなく、(1.10.3以前のバージョンでは) `bash -c "exec {command} ..."`という形式で実行されていました。MCPサーバーの設定画面("Settings → MCP Servers → Add MCP Server"、`POST/PATCH /api/v2/mcp/servers/{server_name}`)にアクセスできるユーザー、またはMCP Toolsコンポーネントを使用してフローを作成できるユーザーは、任意のOSコマンド(`touch`、`rm -rf`、リバースシェルなど)をコマンドとして設定した「サーバー」を追加することができました。このコマンドは、Langflowがサーバーへの接続を試みる際に(サーバーのリスト表示、ツールの読み込み、フローの実行など)、LangflowのプロセスユーザーとしてLangflowホスト上で実行されます。UIがstdioサーバーが起動に失敗したと報告する場合でも、コマンドは実行されます。
デフォルト設定では、`LANGFLOW_AUTO_LOGIN=true`が有効になっているため、`GET /api/v1/auto_login`によって認証情報なしでトークンが発行されます。そのため、デフォルト設定で公開されているインスタンスでは、アカウントなしでアクセス可能です。`AUTO_LOGIN`は開発環境でのみ使用することを想定した設定であり、無効にすると、認証された(管理者ではない)ユーザーがこの脆弱性を悪用できます。
この問題は、以下の2つの段階で修正され、**Langflow 1.10.3**(および1.11.0以降)で完全に修正されました。
- **1.9.0** — #12290で、RESTモデル(`MCPServerConfig`)にコマンドの許可リストと引数/環境変数の検証を追加し、「MCPサーバーの追加」という攻撃経路をブロックしました。
- **1.10.3** — #14036で、実行先(`lfx.base.mcp.util`)にも同様のポリシーを適用し、フロー/設定に埋め込まれた設定や、最終的な実行前の検証も行い、`bash -c`のラッパーを削除しました(プロセスは直接実行され、シェルを経由しません)。
### 影響を受けるバージョン
| パッケージ (PyPI) | 脆弱性あり | 修正済み |
|---|---|---|
| `langflow` | `>= 1.1.2, < 1.10.3` | `1.10.3` |
| `langflow-base` | `>= 0.1.2, < 0.10.3` | `0.10.3` |
| `lfx` | `< 1.10.3` | `1.10.3` |
| リリース | 状態 |
|---|---|
| `1.1.2` – `1.4.x` | MCP Stdioコンポーネント(#5148で追加)が、コンポーネントの`command`フィールドから`StdioServerParameters(command=..., args=...)`を実行しますが、検証は行われません。 |
| `1.5.0` – `1.8.x` | "MCPサーバーの追加"設定ページと`/api/v2/mcp/servers` APIが追加されました(#8388)。保存されたstdio設定は、検証なしで`bash -c "exec {command_str} ..."`を使用して起動されます。 以下のPoCは、そのまま動作します。 |
| `1.9.0` – `1.10.2` | #12290: `POST`/`PATCH /api/v2/mcp/servers`は、許可リストにないコマンドを拒否します。ただし、実行処理には依然として検証がなく、`bash -c`が使用されているため、`MCPServerConfig`を経由しない設定(例えば、フローに埋め込まれたMCP Toolsコンポーネントの値や、調整として渡された値)でも、任意のコマンドを実行できてしまいます。 |
| `1.10.3`+ | #14036: API、フロー実行時、およびプロセスが起動される直前に、共有ポリシー(`lfx.base.mcp.security.validate_mcp_stdio_config`)が適用されます。シェルは使用されません。**修正済み。** |
### 詳細
脆弱な箇所(`src/lfx/src/lfx/base/mcp/util.py`, `MCPStdioClient._connect_to_server`, 1.10.3以前):
```python
server_params = StdioServerParameters(
command="bash",
args=["-c", f"exec {command_str} || echo 'Command failed with exit code $?' >&2"],
env=env_data,
)
```
`command_str`は、ユーザーの`command`と`args`から構築されます。 1.9.0以前の「検証」は`_validate_node_installation`のみで、これはコマンドに`npx`が含まれている場合に、Node.jsがインストールされているかどうかを確認するだけでした。 MCP SDKは、`anyio.open_process`を使用してプロセスを開始するため、コマンドはMCPのハンドシェイクの前に実行されます。そのため、UIに「起動に失敗しました」と表示されていても、コマンドは実行されます。
### PoC(報告された内容、Langflow 1.5.0 – 1.8.x)
"MCPサーバーの追加" → STDIOで、以下の設定を追加します。
```
Name - Test
Command - touch
Arguments - /tmp/pwn
```
または、APIを使用して、`auto_login`(デフォルト設定)から取得したトークンを使用します。
```bash
TOKEN=$(curl -s http://127.0.0.1:7860/api/v1/auto_login | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')
curl -s -X POST 'http://127.0.0.1:7860/api/v2/mcp/servers/testing' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
--data-raw '{"command":"touch","args":["/tmp/pwned_langflow"]}'
```
`/tmp/pwned_langflow` がサーバー上に作成されます。1.10.3 以降では、このリクエストはセキュリティ上の理由から拒否され、エラーメッセージが表示されます。許可されているコマンドは `bash, cmd, docker, node, npx, python, python3, uvx` です。同様のペイロードは、`MCPStdioClient.connect_to_server("touch /tmp/pwned_langflow")` で `MCPStdioSecurityError` が発生し、ファイルが作成されません。`bash -c "touch ..."`、`sh -c ...`、`python3 -c ...`、`node -e ...` などのラッパーも拒否されます。
### 修正
- **#12290** (1.9.0) — `MCPServerConfig` のバリデーター: コマンドの許可リスト (`node`, `python`, `python3`, `npx`, `uvx`, `docker`, および `cmd`/`sh`/`bash` は、それらのいずれかをラップするためのみ許可)、引数に対するシェルメタ文字および危険なキーワードのチェック、環境変数ブロックリスト (`LD_PRELOAD`, `NODE_OPTIONS`, `PYTHONPATH`, `BASH_ENV`, ...)、および Docker の隔離チェック。
- **#14036** (1.10.3) — ポリシーを `lfx.base.mcp.security.validate_mcp_stdio_config` に移動し、すべてのエントリポイント (API、組み込みフロー/設定、非推奨の MCP Stdio コンポーネント、および実行前のチェック) で適用します。また、シェルなしでプロセスを起動します。
```python
command_parts = shlex.split(command_str)
command, args = command_parts[0], command_parts[1:]
validate_mcp_stdio_config(command, args, env) # 実行前の最終チェック
server_params = StdioServerParameters(command=command, args=final_args, env=env_data)
```
後続のセキュリティ強化 (1.11.0, #13530) では、マルチテナント環境向けのより厳格なモードがオプションで追加されました。
### ワークアラウンド (アップグレードできない場合)
- `LANGFLOW_AUTO_LOGIN` を `false` に設定し、Langflow を直接、信頼できないネットワークに公開しないようにしてください。
- Langflow のアカウントは、信頼できるユーザーにのみ提供してください。
### 1.10.3 以降のセキュリティ強化に関する推奨事項
許可リストは、デフォルトで `npx` / `uvx` が任意のパッケージを実行できるようにしています。これは、通常、MCP サーバーが配布される方法です。マルチテナント環境では、管理者は以下の設定も行う必要があります。
- `LANGFLOW_MCP_SERVER_ALLOWED_PACKAGES`: `npx` / `uvx` が実行できるパッケージを正確に指定します。
- `LANGFLOW_MCP_SERVER_INTERPRETER_HARDENING=true` および `LANGFLOW_MCP_SERVER_DOCKER_HARDENING=true` を設定します。
- 1.11.1 以降(#14150)では、カスタムコードの使用を制限する (`LANGFLOW_ALLOW_CUSTOM_COMPONENTS=false`、`LANGFLOW_CUSTOM_COMPONENT_ADMIN_ONLY=true`、または `LANGFLOW_BLOCK_CODE_INTERPRETER_COMPONENTS=true`) ことも、MCP stdio サーバーの使用をスーパーユーザーに限定します。
### 影響
Langflow プロセスのユーザーとして、Langflow ホスト上でリモートコード実行が可能になる可能性があります(CWE-78)。脆弱なバージョンで公開されているインスタンスはすべて影響を受けます。攻撃者がアカウントを持っている場合でも、デフォルトの `AUTO_LOGIN` を使用している場合でも影響があります。報告者によると、インターネットに公開されている脆弱な Langflow サーバーが複数存在することが判明しました。
影響を受けるパッケージ:
- pip (Python) langflow: 影響を受けるバージョン >= 1.1.2、< 1.10.3、1.10.3 で修正済み
- pip (Python) langflow-base: 影響を受けるバージョン >= 0.1.2、< 0.10.3、0.10.3 で修正済み
- pip (Python) lfx: 影響を受けるバージョン < 1.10.3、1.10.3 で修正済み