CVE-2025-34291に学ぶ:CORSとSameSite=Noneでリフレッシュトークンを盗ませない設定

2026年7月、LLMアプリ構築ツール Langflow の CVE-2025-34291 が CISA の KEV(実際に悪用が確認された脆弱性)に追加された。原因は単独のバグというより、よくある2つの設定ミスの合わせ技だ。過度に許容的なCORS設定と、**SameSite=None で発行されたリフレッシュトークンのcookie**。この2つが揃うと、悪意あるサイトがクロスオリジンで認証情報付きリクエストを送り、リフレッシュエンドポイントを叩いてトークンを奪える。フレームワークを問わず起きうる話なので、自分のアプリで同じ穴を塞ぐ設定をまとめる。

何が起きるのか

流れはこうだ。

  1. ユーザーがアプリAにログインしていてリフレッシュトークンがcookieに入っている。
  2. そのcookieが SameSite=None だと、他サイトからのリクエストにも自動で付与される。
  3. アプリAのCORSが「どんなoriginでも許可 + credentials許可」だと、悪意あるサイトBのJSから fetch(A, { credentials: "include" }) が通ってしまう。
  4. Bはリフレッシュエンドポイントを叩き、新しいアクセストークンを取得できる=アカウント乗っ取り。

ポイントは、**Access-Control-Allow-Origin: * と「credentials付き」は本来両立しない**のに、ワイルドカード相当の実装(リクエストのoriginをそのまま反射する)でそれを実質的に成立させてしまう点だ。

対策1:CORSは「反射」せず許可リストで

やってはいけないのは、リクエストの Origin をそのまま Access-Control-Allow-Origin に返す実装。許可originは固定リストで持つ。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Express の例
const ALLOW = new Set([
"https://app.example.com",
"https://admin.example.com",
]);

app.use((req, res, next) => {
const origin = req.headers.origin;
if (origin && ALLOW.has(origin)) {
res.setHeader("Access-Control-Allow-Origin", origin); // 許可リスト内だけ反射
res.setHeader("Vary", "Origin");
res.setHeader("Access-Control-Allow-Credentials", "true");
}
// 許可リスト外は Allow-Origin を付けない=ブラウザがブロック
next();
});

cors パッケージを使うなら、origin にコールバックを渡して同じ判定をする。origin: true(全反射)+ credentials: true の組み合わせは避ける。

対策2:リフレッシュトークンは SameSite=Lax か Strict

リフレッシュトークンのような重要cookieは、クロスサイトで送られないように SameSite=Lax(できれば Strict)にする。None を使うのは、正当にクロスサイトで送る必要がある場合だけで、その時は用途を絞る。

1
2
3
4
5
6
7
res.cookie("refresh_token", token, {
httpOnly: true, // JSから読めない
secure: true, // HTTPSのみ
sameSite: "lax", // クロスサイト送信を抑止(None にしない)
path: "/api/auth/refresh", // 送られるパスを限定
maxAge: 1000 * 60 * 60 * 24 * 7,
});

FastAPI(Langflowと同じPython系)なら次の通り。

1
2
3
4
5
response.set_cookie(
key="refresh_token", value=token,
httponly=True, secure=True, samesite="lax",
path="/api/auth/refresh", max_age=60*60*24*7,
)

対策3:多層で守る

設定を直すだけでなく、次を重ねると堅い。

  • リフレッシュエンドポイントに CSRFトークン(ダブルサブミットcookie等)を要求する。
  • 管理UIを 認証付きプロキシやVPNの背後に置き、公開範囲そのものを絞る。
  • Langflow自体を使っているなら、まず 1.6.9より後のベンダー修正版へ更新する(設定回避は暫定策)。

確認方法

自分のアプリで穴が塞がっているかは、別originのページから試すのが早い。

1
2
3
4
5
// 攻撃者サイトを模した別originのコンソールで
const r = await fetch("https://app.example.com/api/auth/refresh", {
method: "POST", credentials: "include",
});
console.log(r.status); // CORSブロックなら type:"opaque"/エラーになる

許可リスト外originからのcredentials付きリクエストがブラウザにブロックされ、かつリフレッシュcookieが送られていなければ対策できている。

まとめ

CVE-2025-34291は特別なゼロデイというより「緩いCORS × SameSite=Noneの重要cookie」という定番の組み合わせだ。CORSはoriginを反射せず許可リストで判定し、リフレッシュトークンは SameSite=Lax/Strictpath限定にする。これだけでこの手の乗っ取りは大きく減らせる。使っている製品側(Langflow等)は修正版更新を最優先に。


CVE-2025-34291に学ぶ:CORSとSameSite=Noneでリフレッシュトークンを盗ませない設定
https://blog.hashito.biz/2026/07/18/langflow-cve-2025-34291-cors-samesite-refresh-token/
著者
hashito
作成日
2026年7月18日
著作権