[解説] FlowiseのOAuth2認証における深刻な脆弱性:認証不要な情報漏洩とトークン操作
はじめに:なぜフロントエンドエンジニアがこの脆弱性に関心を持つべきか
こんにちは、日本のフロントエンドエンジニアの皆さん。今回は、AIアプリケーション構築ツールFlowiseで発見された、GHSA-wch5-xp77-fxg4 (CVE-2026-70474) という深刻度「High」の脆弱性について解説します。Flowiseはバックエンドツールであり、一見するとフロントエンドとは直接関係ないように思えるかもしれません。しかし、OAuth2認証はウェブアプリケーション開発において不可欠な要素であり、APIの認証・認可に関する知識はフロントエンドエンジニアにとっても必須です。
この脆弱性は、OAuth2フローの設計と実装において、どのような点に注意すべきかという重要な教訓を与えてくれます。特に、API設計におけるワークスペース分離の概念や、認証スキップの危険性について深く理解することは、セキュアなフロントエンド・バックエンド連携を構築する上で非常に役立つでしょう。
脆弱性の概要:Flowise OAuth2 Credential Metadata Leak
この脆弱性の正式名称は「Flowise: Cross-Workspace OAuth2 Credential Metadata Leak」です。Flowiseにおいて、OAuth2クレデンシャルを管理するエンドポイントに以下の3つの深刻な問題が発見されました。
1. **クロスワークスペースでのクレデンシャル情報へのアクセス**: 認証済みユーザーが、自身のワークスペース外にある他のワークスペースのOAuth2クレデンシャルに関するメタデータ(client_id, scope, redirect_uriなど)を窃取できる可能性があります。
2. **認証不要なトークンインジェクション**: 認証されていない攻撃者が、偽のOAuth2コールバックをforge(偽装)することで、任意のクレデンシャルに任意のアクセストークンを書き込むことができます。
3. **認証不要なトークンリフレッシュと窃取**: 認証されていない攻撃者が、任意のクレデンシャルのOAuth2リフレッシュトークンを使用して、新しいアクセストークンを取得し、それを窃取することができます。
これらの問題が複合的に作用することで、Flowiseインスタンス上の他のユーザーが連携している外部サービス(Microsoft 365, Google Workspaceなど)へのアクセス権が、認証されていない攻撃者によって奪われる可能性があります。
根本原因:ワークスペース分離の欠如と認証スキップ
この脆弱性は、主に以下の2つの根本原因に起因します。
FlowiseのOAuth2クレデンシャルを処理する複数のエンドポイント (`/authorize`, `/callback`, `/refresh`) は、クレデンシャルをデータベースから取得する際に `id` のみで検索し、`workspaceId` によるフィルタリングを行っていませんでした。これは「Insecure Direct Object Reference (IDOR)」の一種と言えます。
本来、ユーザーがアクセスできるクレデンシャルは、そのユーザーが所属するワークスペースに紐づくものに限定されるべきです。しかし、この実装の不備により、攻撃者はクレデンシャルID(UUID)さえ知っていれば、どのワークスペースに属するクレデンシャルでも参照・操作できる状態でした。
例(脆弱なコード):
```typescript const credential = await credentialRepository.findOneBy({ id: credentialId // Missing: workspaceId filter }) ```
一方、同じFlowiseの他のサービスでは、以下のように `workspaceId` で適切にフィルタリングされており、この脆弱性が特定のOAuth2関連の処理に限定されていたことが分かります。
```typescript const credential = await appServer.AppDataSource.getRepository(Credential).findOneBy({ id: credentialId, workspaceId: workspaceId // <-- Workspace scoping present }) ```
さらに深刻な問題は、`/api/v1/oauth2-credential/callback` と `/api/v1/oauth2-credential/refresh` の2つのエンドポイントが、認証チェックを完全にスキップするホワイトリストに含まれていたことです。
通常、APIエンドポイントへのアクセスにはJWT検証やAPIキーチェックなどの認証が必要です。しかし、これらのエンドポイントはホワイトリストに登録されていたため、どんなユーザー(または認証されていない攻撃者)でも直接アクセスできてしまう状態でした。
```typescript export const WHITELIST_URLS = [ // ... '/api/v1/oauth2-credential/callback', '/api/v1/oauth2-credential/refresh', // ... ] ```
ワークスペース分離の欠如と、この認証スキップの組み合わせにより、認証されていない攻撃者が、特定のクレデンシャルIDさえ知っていれば、あらゆるワークスペースのクレデンシャルに対して「トークンインジェクション」や「トークンリフレッシュ・窃取」を実行できることになります。
具体的な攻撃シナリオ
Flowiseに認証済み(どのワークスペースでも良い)の攻撃者は、他のワークスペースにあるOAuth2クレデンシャルのUUIDを知っていれば、そのクレデンシャルの認証URLを生成させることができます。この認証URLには、被害者の `client_id` や `scope`、`redirect_uri` といった機密性の高いメタデータが含まれています。
```bash POST /api/v1/oauth2-credential/authorize/<VICTIM_CREDENTIAL_UUID> Cookie: connect.sid=<ATTACKER_SESSION> ```
これにより、攻撃者は被害者のOAuth2アプリケーションの構成情報を知り得ます。
このシナリオが特に危険です。`callback` エンドポイントが認証不要であり、かつ `state` パラメータがクレデンシャルIDとして利用されているため、攻撃者は以下の手順で任意のトークンを注入できます。
1. 攻撃者が自身でOAuth2プロバイダーを制御するか、正規のフローをMiTM(中間者攻撃)する。
2. 被害者のFlowiseインスタンスに対して、認証されていない状態で偽のコールバックリクエストを送信する。`state` パラメータには被害者のクレデンシャルUUIDを指定し、`code` パラメータには攻撃者によって制御された認可コードを指定する。
```bash GET /api/v1/oauth2-credential/callback?code=ATTACKER_AUTH_CODE&state=<VICTIM_CREDENTIAL_UUID> (No authentication required) ```
Flowiseサーバーは、この偽の `code` をクレデンシャル設定された `accessTokenUrl` に送り、返ってきたトークンを被害者のクレデンシャルデータとして上書き保存してしまいます。これにより、被害者の外部サービス連携は攻撃者によって乗っ取られることになります。
`refresh` エンドポイントも認証不要であるため、攻撃者は被害者のクレデンシャルUUIDを知っていれば、そのクレデンシャルのリフレッシュトークンを利用して、新しいアクセストークンを生成し、それを応答として直接取得できます。
```bash POST /api/v1/oauth2-credential/refresh/<VICTIM_CREDENTIAL_UUID> (No authentication required) ```
サーバーは格納されているリフレッシュトークンを使用してアクセストークンを更新し、その新しいアクセストークンをレスポンスボディに含めて返してしまいます。攻撃者はこのアクセストークンを使って、被害者の連携サービス(Microsoft Graph、Google APIsなど)にアクセスし、機密データを閲覧したり、操作したりすることが可能になります。
フロントエンドエンジニアへの教訓と対策
この脆弱性はバックエンド実装の問題ですが、フロントエンド開発を行う皆さんにとっても重要な示唆を与えます。
・**OAuth2 `state` パラメータの適切な利用**: `state` パラメータは、CSRF攻撃を防ぐために使われるべきであり、単なるIDとして利用すべきではありません。暗号学的に安全なランダムな文字列を生成し、セッションに紐付けて検証することで、フローの整合性を保つ必要があります。
・**APIエンドポイントのアクセス制御**: 全てのAPIエンドポイントは、最低限の認証・認可チェックを通過する必要があります。ホワイトリストで認証をスキップする際は、その機能が本当に認証不要であるか、最大限の注意を払って検討すべきです。特に、機密情報を取り扱うエンドポイントや、データの変更・取得を伴うエンドポイントは、厳格な認証・認可が必要です。
・**ワークスペース/テナント分離の徹底**: マルチテナント型アプリケーション(Flowiseのように複数のワークスペースを扱うシステム)では、ユーザーが自身のワークスペース内のデータのみにアクセスできることを保証する、厳格なアクセス制御が必須です。データベースクエリを行う際は、常にユーザーの `workspaceId` や `tenantId` でフィルタリングを行う習慣をつけましょう。
・**機密情報の取り扱い**: アクセストークンなどの機密情報は、可能な限りサーバーサイドで安全に管理し、クライアントサイドには直接返すべきではありません。必要な情報のみを最小限の権限でクライアントに提供する「最小権限の原則」を遵守しましょう。
1. **全クレデンシャル検索に `workspaceId` を追加**: OAuth2関連のルートを含む、全てのクレデンシャル取得処理で `workspaceId` によるフィルタリングを必須とする。
2. **`WHITELIST_URLS` から `/callback` および `/refresh` を削除**: これらのエンドポイントに対する認証チェックを復活させる。もし認証スキップが必要なら、署名付きで時間制限のあるステートトークンなどの厳格な検証メカニズムを導入する。
3. **`state` パラメータの強化**: OAuth2コールバックの `state` パラメータを、暗号学的に安全なランダムなnonce(一度きりの値)にし、ユーザーのセッションと紐付けて検証する。
4. **`access_token` のレスポンスボディからの削除**: `/refresh` エンドポイントのレスポンスボディに新しい `access_token` を直接返さない。トークンはサーバーサイドのクレデンシャルデータとしてのみ更新・保存されるべきです。
まとめ
FlowiseのOAuth2脆弱性は、多要素が絡み合った複合的な問題であり、その結果として認証不要での外部サービス乗っ取りという深刻な影響をもたらします。フロントエンドエンジニアとしては、直接バックエンドのコードを書く機会は少ないかもしれませんが、OAuth2フローの正しい理解、APIセキュリティに関する知識、そしてクロスワークスペースでのデータ分離の重要性を認識することは、セキュアなアプリケーション開発において不可欠です。
皆さんの日々の開発業務においても、常にセキュリティを意識した設計と実装を心がけましょう。