FastAPI 0.140.0-0.141.1 では、レスポンスモデルを指定せずにルートがプレーンな辞書(dict)やリスト(list)を返すと、Pydantic の Secret クラスでラップされた生の値を露出させてしまう可能性があります。この漏洩により、開発者が隠そうとしたパスワード、API キー、その他の認証情報が明らかになる恐れがあります。

このバグが重要な理由

FastAPI は、ビュー関数の戻り値の型を検査することで JSON レスポンスを構築します。レスポンスモデルを指定している場合、FastAPI はオブジェクトを Pydantic に渡し、Pydantic は SecretStr"**********" としてマスクします。影響を受けるバージョンでは、フレームワークは組み込みの SecretStr 型のみを認識します。Secret を継承したクラス(またはカスタムのシークレット型)を使用し、そのオブジェクトを生の辞書やリストの中に含めて返すと、FastAPI は汎用的なオブジェクトから辞書への変換(object-to-dict conversion)にフォールバックします。その変換プロセスが、実際のシークレット値を保持しているプライベート属性にアクセスしてしまい、値を変更せずにクライアントへ送信してしまいます。

この漏洩は、以下の3つの条件すべてが満たされた場合にのみ発生します:

  • シークレット型が Pydantic の Secret 基底クラスを継承している。
  • ルートにレスポンスモデルが宣言されていない
  • ビューがプレーンな dict または list の中にシークレットを含めて返している。

今すぐシークレットを保護する方法

  • レスポンスモデルを宣言する: シークレットを含むデータを返す可能性のあるすべてのエンドポイントに対して、レスポンスモデルを宣言してください。これにより、FastAPI は Pydantic にシリアライズを任せることができ、値が正しくマスクされます。
  • シークレットを Pydantic の BaseModel フィールド内にラップする: 生のコンテナを返すのではなく、シークレットを BaseModel のフィールドとして扱ってください。モデルのフィールド型として認識可能なシークレットクラスを指定することで、適切な処理が保証されます。
  • カスタム JSON エンコーダーを登録する: 現在の戻り値のスタイルを維持する必要がある場合は、シークレットのサブクラスに対してカスタム JSON エンコーダーを登録してください。エンコーダーは、マスクされた表現("**********")を返すように設定できます。

重要度とコミュニティの対応

この問題の重要度は低いです。発生させるには特定の構成が必要ですが、認証情報の偶発的な露出は、特に公開 API やレスポンスをログに記録するサービスにおいてリスクとなります。

まとめ: レスポンスモデルを省略すると、意図的に作成したシークレットのラッパーがデータ漏洩の原因になり得ます。明示的なレスポンスモデルの追加やカスタムエンコーダーの使用は、FastAPI が組み込みの修正をリリースするまでの間、認証情報を隠し続けるための、手軽で信頼性の高い方法です。