React2Shell シナリオ:

*   **文脈**: React フロントエンドアプリケーションとバックエンドシェルスクリプト環境の相互作用を描出した仮定の物語。
*   **プロット**: ユーザーが React 経由でデータ可視化をリクエストすると、それに応じてシェルスクリプトによってバックエンドプロセスが実行され、人工データを生成した後に応答が行われる。
*   **結末**: シェルスクリプトは出力を JSON 形式に整形し、React はそれをパースしてページ更新を行わずに動的に UI に描画する。

2026/05/09 1:39

React2Shell シナリオ: * **文脈**: React フロントエンドアプリケーションとバックエンドシェルスクリプト環境の相互作用を描出した仮定の物語。 * **プロット**: ユーザーが React 経由でデータ可視化をリクエストすると、それに応じてシェルスクリプトによってバックエンドプロセスが実行され、人工データを生成した後に応答が行われる。 * **結末**: シェルスクリプトは出力を JSON 形式に整形し、React はそれをパースしてページ更新を行わずに動的に UI に描画する。

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

以下の改良版は、すべての重要な情報を保持しつつ、より流暢で明確な表現のためやや文句を厳密化しています:

概要:

React は、Next.js と React Server Components で使用される内部プロトコル「Flight」に見つかった、Critical Remote Code Execution(RCE)脆弱性により乗っ取られました。この脆弱性は「React2Shell」と呼ばれています。原因はランタイム型の強制が不足していることにあります:TypeScript アノテーションを使用していても、Flight プロトコルはクライアントとサーバー間で受け渡しされる不信なデータに対してプロトタイププロパティ(例:

Array.prototype.push
)との検証を行わずに処理します。攻撃者は、クライアントとサーバー間で渡されるオブジェクトに悪意のある振る舞いを注入し、thenable オブジェクトを待ち受ける際 React が任意のコードを実行することを強制することでこの脆弱性を exploit しました。

この脆弱性は 2025 年 11 月 30 日に報告され、CVE-2025-55182 の下で約 17 時間でパッチ適用されました。Meta の素早い対応は称賛に値しますが、Flight に関する公的なドキュメントが不足していること、そして事故が週末に発生したことは、React のセキュリティ姿勢および信頼性に対する懸念を引き起こしました。この事例は、TypeScript が不信な入力からの安全を保障しないことを示すとともに、将来のエコシステム全体の脅威を防ぐために内部プロトコルに関する厳格な公的な仕様を急務としていることを浮き彫りにします。開発者は即座にアップデートを行うよう推奨されます。

本文

2025 年 11 月 30 日に、私はメタ社へ重大なリモートコード実行(RCE)脆弱性を「React2Shell」として報告しました。12 月 3 日には、メタ側から修正パッチと公衆向けの注意喚起(CVE-2025-55182)が発行され、開発者への即座なアップデート要請が通告されました。

皮肉にも、私は React の脆弱性を特定しようとはじめからないました。現代の Web アプリケーションに対するハッキング技術を高度化する目的で、あるプロトコルの仕組みを理解したいというだけで探訪を開始したのです。しかし、その代償として、数百万のウェブサイトに影響を及ぼす重大な脆弱性へと、抜け出ることのできない穴に落ち込んでしまいました。

また、本件の詳細についてはシルヴィー氏によるブログ投稿「React2Shell」をお読みいただくことをお勧めします。また、その後に巻き起こったさまざまな出来事についても触れておきます。

※当記事の日付はニュージーランド標準夏時間(NZDT、GMT+13)で表示されています。 これは、シルヴィー氏の投稿(GMT-7)やメタ社(GMT-8)で使用されているタイムゾーンとは異なります。

月曜日:空へ飛び立つ

プロフェッショナルなハッカーとして、2025 年 11 月 24 日の月曜日は平凡な業務の一日が始まりました。レポートの最終確認や新たなプロジェクトの着手などです。しかしその午後、好奇心と苛立ちに駆られて頭の中でスイッチが切り替わり、振り返ることのできない穴へとダイブすることになりました。

背景

近年、私は Next.js という非常に人気のある React ベースのフレームワークで構築された多くの Web アプリケーションのペネトレーションテスト(APT)を行ってきました。Next.js は「React サーバーコンポーネント(RSC)」を活用し、サーバー側でコンテンツを効率的にレンダリングしてユーザーのブラウザへ送信したり、「React サーバー関数」(旧称:サーバーアクション)を通じてユーザー操作がシームレスにサーバー側の JavaScript コードを呼び出せるようにしたりします。

当初、サーバーアクションは導入された際、多くの冷笑を浴びましたが(この画像を circulating したことは記憶にありますか?)、本質的に非常に優れた機能であるため普及しました。あるコードベースにおいて、開発者はサーバー側でコードを書き、クライアント側からそのコードを呼び出すことができます。

これらの機能を支えるために、ブラウザとサーバーの間を行き来するメッセージング方法が必要となり、既存の技術だけでは不十分でした。そこでリアクトチームは新たな仕組みを開発しました。サーバー関数を使用した Web アプリケーションのペネトレーションテストに携わった方なら、この少し珍しいリクエスト形式にはお馴染みのはずです。

0=[{ "a": "$$undefined", "b": "$1:foo:bar" }]&1=...

業界全体として、私たちはみな「まあ、JSON にちょっとした装飾が加えられたものに見えるだけだ」と考え、ここに明らかに追加される攻撃表面(Attack Surface)を軽視して、従来のアプリケーションのようにテストを進めてきた過去があります。私もその一人でした。

スイッチが切れた場所

この月曜日の午後、私はこの形式について学び続ける強い衝動に襲われました。理解せねばなりませんでした。私を知っている方々が証言するように、私は決して半分では物事をしません。問題は徹底的に分解するまで喜んで地球の果てまで向かう人物です。

Web アプリケーションへのハッキングの多くは、開発者が想定していないようなものをアプリケーションへ投げつけることに過ぎません。もしこのプロトコルが Web アプリケーションに対して新たに異なる攻撃ベクトルを提供できれば、それを知る必要があったのです。もしかしたら方法論を公開できるかもしれません!

さて、それがいったい何でしょうか?

そこで文書を探してみるものの──あっ…… プロトコルの仕様は存在せず、わずかな情報しか見つかりませんでした。

そもそもこのプロトコルにはどのような名前があるのでしょうか?「React2Shell」の公開以前は、このプロトコルの正式名称さえ発見するのが驚くほど困難でした。フォーマットに至っては言うまでもありません。

探した結果、X(旧 Twitter)上のいくつかのスレッドに RSC に関する議論が見つかりました。

すでに Flight という名の探索に夢中でしたが、「文書なし、コードのみ」という状況は、私の動機をさらに燃え上がらせたものです。私の運命は封じられていました。Flight エグプートになるまで休むことを許されませんでしたが、翌朝にはプロトコルの基礎的な仕組みを理解し、これに止めることはできませんでした。

Flight 101

Next.js は開発者に、クライアント側とサーバー側のコード間で複雑な JavaScript オブジェクトを魔法のように渡す能力を提供しますが、そこには単純な JSON で表現できないオブジェクトも含まれます。Flight はこの問題を解決するために、より高度なデータ型(Date、BigInt、Map など)、参照(循環参照を含む)、Promise(非同期で到着するデータ)などのサポートを追加しました。

基本的には JSON ベースですが、Flight メッセージは「チャンク」に分割されます。各チャンクは通常、フォーム要素として送信され、非同期かつ順序が異なるように到達することがあります。特殊な

$
シNTAX が Flight タイプを表します。以下に示す例では、$D は日付を、$x は別のチャンクの参照を、$x:y はプロパティの選択を示しています。

0 = {
    "email": "[email protected]",
    "updated": "$D04 Dec 1995 00:12:00 GMT",
    "details": "$1"
}
&1 = {
    "firstName": "$2",
    "lastName": "$3:foo"
}
&2 = "John"
&3 = {
    "foo": "Doe"
}

これをパースした結果、サーバーのメモリ空間では以下のように解決されます:

{
    "email": "[email protected]",
    "updated": Date(Mon Dec 04 1995 13:12:00 GMT+1300 (New Zealand Daylight Time)),
    "details": {
        "firstName": "John",
        "lastName": "Doe"
    }
}

「安全チェックの明らかな欠落」

Flight は重要に、オブジェクトのプロパティを参照する機能を備えています。では、オブジェクトそのものではなく、そのプロトタイプ上に存在するプロパティを参照しようとした場合、どのようなことが起こるのでしょうか?

なんと驚くべきことに、継承されたプロパティ(この場合は

Number.prototype.toString
)を参照する Flight メッセージをサーバーへ送信すると、それを正常に取得し、攻撃者が制御可能なオブジェクト内に配置できてしまいます。

0 = {
    "foo": "$1:toString"
}
&1 = 123

// リザルト:
0 = {
    "foo": Number.prototype.toString
}

この事象は、Next.js の原作者であり Vercel の創設者であるギルベルト・ロウク氏によって、「明らかな安全チェックの欠落」として説明されました。しかし当時は、あまり深く考えませんでした。「過剰に寛容すぎる」ように見えたかもしれませんが、標準的な JavaScript のプロパティ検索セマンティクスに沿っていたのです。リアクトは最も戦績豊富なフレームワークの一つであり、そのため問題ないはずです。

火曜日:Flight を武器化

初期の目標

最初の調査において、私は以下の 2 つのポイントに焦点を当てました:

  • 開発者は頻繁にユーザー入力の検証をおろそかにします。
  • Flight は攻撃者に、通常の JSON よりもはるかに複雑なオブジェクトを送信させることができます。

これは強力な組み合わせになり得ます。Flight 自体の脆弱性を探すわけではなく(まだ)、Flight を悪用して検証が不十分な Next.js アプリを攻められるかを見極めるつもりでした。

私がレビューした Almost Every Next.js アプリケーションには、このような攻撃面が含まれており、多くのオープンソースプロジェクトでも同様です。そこで私は Flight を武器化し、エクスプロイト方法論を開発し、いくつかの CVE を獲得しようと考えていました。 (補足:React2Shell が修正されたことで、これらの攻撃ベクトルも閉ざされ、当初のアイデアは意味をなさなくなりました。)

例 1 - タイプ強制(Type Coercion)

以下のような React サーバー関数を開発者が実装するケースですが、そこに微妙な脆弱性が潜んでいます。

async function sayHello(name: string): string {
    'use server'
    return 'Hello, ' + name + '!'
}

これは

name
が文字列であると考えていますが、それはただの希望的観測に過ぎません。実際には、悪意あるクライアントが Flight を介して送信できる何らかのオブジェクトかもしれません。もし攻撃者が独自のオブジェクトを送り込み、そのオブジェクトに
toString
メソッドを参照させた場合どうなるでしょうか?サーバー側で文字列連結を試みると、自動的に
toString
関数が呼び出されてしまいます!

このミスを見逃すことは特に簡単です。TypeScript の型注釈

: string
が型の安全性を与える幻想を与えますが、実際にはランタイムで強制されるわけではありません。

例 2 - 明示的な関数呼び出し

toString
の例は発見しやすいですが、攻撃する難易度としては最も高かったように見えます(単一の関数呼び出しで制御可能な引数が一切ないため)。 一方、この例には遥かに多くの攻撃面があります。開発者は再び
str
を文字列であると考えていますが、攻撃者は
replaceAll
に悪意のある関数を配置し、その関数の 2 つの引数をすべて制御できます。

async function replaceStuff(str: string, before: string, after: string): string {
    'use server'
    return str.replaceAll(before, after)
}

型の安全性という幻想

「しかし Lachlan(私自身),これらのパラメータには明らかに型があるのでは?」と感じるかもしれませんが。

TypeScript はビルド時の分析のみを実行し、信頼できないデータのランタイムでの型検証や強制を行うことはできません。この二刃の剣により、「ユーザー入力が有効な型である」という幻想を信じ込ませることができても、実際には何もチェックされていません。開発者が特定の値を期待しているにもかかわらず、攻撃者は任意のオブジェクトを送信できます。

エクスプロイト - ゲームのルール

Flight は弾薬(武器になる可能性)を提供していますが、それを実際に実用的な兵器に変えることは困難でした。

これを CTF(Capture The Flag)パズルのように捉えると:

  • アプリケーション開発者が脆弱なコードを記述した場合(前述の例など):
    • 攻撃者指定の関数が一度呼び出される
    • 攻撃者は 0 個から N 個の引数を制御できる
    • 私たちが指定する関数や、その引数の構造はすべて Flight メッセージに由来しなければならない

React ドキュメントと Flight コードをざっと見ると、以下のデータ型を使用できます:

  • プレーンなオブジェクト、アレイ、文字列
  • JSON で表現できない定数(Infinity, BigInt, NaN など)
  • Date
  • Set, Map, 配列型(Uint8Array など)
  • 将来到着するチャンクを約束する Promise
  • サーバー関数の参照
  • 上記いずれかのプロパティまたはメソッド

最後の点が最も重要であり、ここから関数への参照が可能になります。例えば、アレイを作成して

Array.prototype.join
にアクセスしたり、Date を作成して
Date.prototype.getYear
にアクセスしたりできます。

いかなる関数においても、

.constructor
を使用することで Function コンストラクタにアクセスでき、これは JavaScript で任意のコードを実行できる少なさの手段の一つです。まず実行したいコードを渡して呼び出し、返却される関数を呼び出すと、その時点で任意のコードが実行されます。

もし

Function("console.log('evil')")()
を強制できれば、勝ちです。「ゲームのルール」に従って一度関数を呼び出すのは簡単ですが、その結果を再び呼び出すことはほぼ不可能に見えました。

この時点で、私は数多くの友人に助言やアイデアを求めました。特に長年の友人であるシルヴィー・マイヤー氏には感謝しています。彼女がこの種類の CTF チALLENGE に非常に長けており、私がいまだに Flight について研究を進めている最中、前述の「ルール」についても共有する機会がありました。彼女は自身もこのサガについてのブログ投稿を持っており、Python jail challenge など、同様のスキルセットを持つ素晴らしい記事も多数執筆しています。

水曜日:馬鹿げている循環

通常の業務の日々を調整しながら進めていましたが、この週を通じて私は新しい執念に駆られ、目覚めている時間全てをそこに費やしていました。それにドーパミンの影響で睡眠は不可能でした。もともと JavaScript について非常に知識を持っていたと自負していたのに、その癖や、Flight が提供するアクセス可能な機能、そしてそれをどう不正な振る舞いさせるかを学び続けました。

シルヴィー氏とは Flight を武器化するために多くの時間を過ごしましたが、毎回何か有望に見えたとしても、それを RCE を達成するための有用な行為にするために試みても失敗しました。しかし各反復において、私はこの奇妙なプロトコルとその提供してくれる機能について徐々に精通していきました。

興味深いことに、私たちはどちらも以下の精神的なループに陥り続けていました:

  • 後々振り返って個人的に反省すると非常に奇妙です。明らかに私は認知上の目隠し(Blind Spot)を持っていたのです。React のセキュリティ面でのほぼ完璧な記録があったため、このような脆弱性を発見する概念自体が馬鹿げているように思えました。私が上記で示した脆弱なアプリケーションコード例(信頼できないユーザー入力を文字列として扱うなど)は、実は React 自体に含まれていました!これは私が潜在的な攻撃経路としてそのようなケースをほぼ無視させる原因となりました。
  • この時点では、React/Flight が悪意のある関数を構築することを可能にし、脆弱なアプリケーションが実際にそれを呼び出すことだけが最善の期待でした。

木曜日:最初の突破口

木曜日の午後某時、React2Shell の開発につながる最も重要な要素の一つを見出しました。

高級フレームワーク(Next.js など)が入ってくる Flight ペイロードをリアクトにデコードさせた際、

await decodeReply(...)
を呼び出します。これは一見合理的ですが、巧妙な裏面を隠しています...

素早い歴史講座 -コールバックと Promise

サーバーサイドの JavaScript コードは単一スレッドで動作し、I/O はネイティブコードによる背景スレッドで処理されます。JS の世界では、背景タスク完了時にエンジンに呼び出させる「コールバック」関数を渡します。

doTheThing(123, function(result) {
    doTheNextThing(result.blah, function() {
        moreStuff(...)
    })
})

しかしこれは非常に整理が悪い状態になります。入ってくるリクエストを処理するために 10 段階のデータベース呼び出しが必要な場合、10 層もネストが必要となり「コールヘル(Callback Hell)」に陥ります。これからのために「Promise」という概念が考案されました。未来の値への約束を表す標準的な形式です。

Promise を使用すれば、直接的なコールバック関数を渡す代わりに

.then(...callback...)
を呼び出します。
.then
ハンドラが別の Promise を返せば、さらに
.then
をチェーンできます。各呼び出しごとにネストする必要がなく、単に別の
.then(...)
を追加するだけです。

doThething(123)
    .then((result) => doTheNextThing(result.blah))
    .then(() => moreStuff())
    .then(() => andEvenMoreStuff())

これは大きな進歩でしたが、依然として特に人間工学的ではありませんでした。しかしその後、ECMAScript 2017 が最終的に async/await を JS に導入し、非同期コードを同期コードのように記述することを可能にしました:

let result = await doTheThing(123)
await doTheNextThing(result.blah)
await moreStuff()
await andEvenMoreStuff()

async
とマークされた関数は呼び出されただけで Promise を返し、すべての
await
は Promise に対して
.then(...)
を呼び出すだけであり、async/await が Promise と完全に互換性を持つようになりました!

しかし…… Promise が ECMAScript 2015 で標準化される前に、コミュニティによって多数の Promise インプレメンテーションがあり、挙動が異なっていました。すべて共通していたのは

.then(...)
の慣習です。これに従うオブジェクトを「thenable」と呼びます——文字通り、
.then()
が可能な任意のオブジェクトです。

内部では、

await
Promise.resolve
を呼び出し、寛容的に thenable を呼び出します。

> await { then: console.log }
function (), function () // 注入された resolve, reject コールバックが表示される

ただし最後の詳細があります:一度に

await await foo()
する必要はあるでしょうか?ありません!thenable が別の thenable に解決すれば、自動的にそれも呼び出されます。

> await {
    then: resolve1 => resolve1({
        then: resolve2 => resolve2(123)
    }) 
}
// 123

Thenable の悪用

では、Flight に以下のデータをシリアライズして送信したらどうなるでしょうか?

{
    then: Array.prototype.push
}

await decodeReply(...)
はまず Flight パーサーを実行しますが、その後別の thenable を見つけると、攻撃者供給の関数を呼び出します!

リクエストは待機状態になります。なぜなら我々の偽の Promise は決して解決しないためです。しかしメモリを調査すると、ランタイムが実際には

.then(resolve, reject)
を作成したオブジェクト上で呼び出したことが分かります:

{
    then: Array.prototype.push,
    0: [Function (anonymous)],
    1: [Function (anonymous)],
    length: 2
}

これは React において意図的ではないと感じた最初の振る舞いでした。それまで Flight が提供していたものはすべて……「過剰」に見えたかもしれませんが、私の外部視点からは設計上予想される内容のように見えました。

さらに一段階進めると、thenable ペイロードを別の thenable に解決するように作成すれば、無制限の関数呼び出しをチェーンできます。しかし当時、この重要性を十分に認識していませんでした。すでに攻撃者制御のオブジェクト上の関数を暗黙的に呼び出す方法を持っていたため、新たな能力のように感じませんでした。

金曜日:非常に近くなった

金曜日の早朝に、ゲームを根底から変える一大転換点を経験しました。「Flight を使ってアプリケーションを攻められるか?」という問いは、「Holy moly, React Flight 自体に重大な脆弱性がある可能性が極めて高い!」へと急速に変化しました。

ここで再び希望と絶望の繰り返しが始まりました。React に重大な脆弱性が残っているかもしれないと思いましたが、すぐに想像していた通り機能しませんでした。

React の内部へのアクセス

これまでは Flight で参照できる JavaScript 標準ライブラリに焦点を当てていましたが、もう一つのガジェットがずっと目の前にありました。Flight で別のチャンクを参照する際、通常は

$x
を使いますが、もう一つオプションがあります:
$@x
を使うと、後から到着するチャンクの Promise を作成します。React はこれをどのように実装しているのでしょうか?新しいチャンクを作成し、Chunk という React 固有のオブジェクト(Promise から継承)を作成します。

では以下のメッセージを送信したらどうなるでしょうか?

0 = {
    "then": "$1:then"
}
&1 = "$@2"

これが発生します:

Error: An undefined error was thrown, see here for more info: https://nextjs.org/docs/messages/threw-undefined
at ignore-listed frames

一体何が起きましたか??

  • "$@2"
    は新しい
    Chunk(...)
    を構築した
  • $1:then
    から
    Chunk.prototype.then
    を引き出した:React の実装する
    .then
  • Flight は攻撃者制御のオブジェクトを返す
  • await
    .then(...)
    を呼び出し、React の実装を呼んだが、これは React ではなく攻撃者のオブジェクトに対して

コード分析によると、React はチャンクの

.status
を検索しようとしたが、通常のステートが見つからず、Promise を拒否(エラーをスロー)し、
.reason
にエラーを設定した。しかし、攻撃者制御のオブジェクト上の
.reason
は undefined である。

Chunk.prototype.then = function <T>(
    this: SomeChunk<T>,
    resolve: (value: T) => mixed,
    reject: (reason: mixed) => mixed,
) {
    const chunk: SomeChunk<T> = this;
    ...
    switch (chunk.status) {
        // ... (normal cases) ...
        default:
            reject(chunk.reason);
            break;
    }
}

第 1 回アプローチ - 悪意のあるサーバーマニフェスト

私はこれで React に RCE があることに確信しました。

Chunk は Flight が実装されている基本オブジェクトであり、多くの内部ステートを保持しています。Flight を強制して私のオブジェクトに対して

Chunk.prototype.then
を実行し、その内部ステートのすべてを偽装できるため、「偽のチャンク」を作成できます。

私はすでに Flight に慣れていたため、RCE への経路は明白に見えました。Server Functions を使用するには、React は「サーバーマニフェスト」が必要です。これはユーザーが指定できる Server Function ID と、サーバーが実行するモジュール名および関数をマップした厳密なリストです。

私のアイデアは以下の通りでした:

  1. Flight を実行して
    Chunk.prototype.then
    を私のオブジェクトに対して適用する
  2. 私たちの「偽のチャンク」内でサーバーマニフェストを上書きし、ID を
    child_process
    exec
    関数にマップすることでシェル実行権限を付与する

すぐにそのためにペイロードを構築しましたが、動作せず、デバッグガーで1時間慌ててもなぜか分かりませんでした。

成功させるまでまだ遠く感じたので、この時点でシルヴィー氏と個人的に連絡を取りました。最新の発見を共有しました。私の頭の中では、さらに数週間の研究が必要と感じるようになりました。しかし、彼女とのテスト環境再現中にデバッガーの接続を修正し、React が

./child_process.dev.js
を読み込み実行しようとしているかを見ることができました?!

React は Node のモジュールシステムを直接使わないため、Webpack や Turbopack を使用します。child_process は Webpack 内の有効なモジュールではなかったため、ディスク上のファイルとして child_process モジュールを探そうとしました。

再び……

つまり、私のペイロードは意図した通り機能していましたが、実際に

child_process
モジュールを読み込ませることに成功せずでした。

その後、シルヴィー氏と共に利用可能なモジュールを調べるようになりました。彼女はファイル書き込みが可能にするモジュールに注目し、私はデフォルトで利用可能な潜在的に有用なモジュールを徹底的に列挙しました。

その夜のどちらも成功せず、夜明けと共に現実の業務の山積みに対処する必要があり、一日ほど棚に上げてしまいました。

RCE

金曜日の深夜、エクスプロイトチェーンを構築する方法への気づきを得ましたが、土曜日の早朝にかけてようやく全てが繋がり、React2Shell が誕生しました。

非常に複雑なエクスプロイトチェーンでした。複数の関数呼び出しを経由して最終的に

Module._load
を呼び出すことで、Node.js 内で任意の JavaScript コードを実行するモジュール(name: "module")にアクセスできました。ただし、内部ステートを修正して制限を乗り越えるために多くの複雑な操作が必要でした。正直言って、それが何を意味するのか理解していないかもしれませんが、GitHub にあります。

ショックと不信感の中にありました。この時点で、分析脳は私が実際に RCE を発見したのではなく、睡眠不足による幻覚を見ている可能性の方が統計的に高いと考えました。その後どうすればよいか分からず、ラップトップを閉じてほぼ日曜になるまで眠りました。

日曜日:RCE の洗練化と開示

サーバーマニフェストの偽装は望ましくないアプローチでした。RCE は動作しましたが、Webpack で生成されたモジュール ID が正しいことに依存しており(部分的にのみ一致)、Node.js ランタイム上での動作など多くの要因に影響されました。

そのため、第一原理から働きかけ、非常にすぐに優美な解決策を見つけました。

Function("evilCode();")();
のアイデアに戻り、React の Chunk コード内で我能する引数を持つ関数を呼び出す場所を探し、その結果をどこかで呼び出されるような場所に配置する必要がありました。新しい視点で、React が内部ステートから来る関数を呼び出すと考えられた Chunk コード内の場所を集中させました。一例として、アップロードされたファイルの blob への参照を作成する際に、
$Bx
コードは
_formData.get(...)
を呼び出します。これは私たちがほぼ完全に制御できる引数を使用できます。これを使用して悪意のある関数を構築し、最終的な
then
プロパティに結果を植えることで、RCE が呼び出されました。これが Meta へ提出した PoC です。

開示

Meta への報告を送った際、再現手順は恐るべきほど簡単でした。実質的には:新しい Next.js/React アプリをインストールし、スクリプトを実行すれば RCE でした。

驚くべきことに、週末であっても、Meta チームはトリイージ、再現、そして私の提出を確認するまでに約 17 時間を費やしました。

Meta 全体と React チーム(Verceel を含む)と働くのは本当に楽しいものでした。Zoom や Slack 上で非常に才能のあるスタッフたちと話をする中で、彼らがこの問題を取り扱っている様子の深刻さに気づきました。

開発者たちは昼夜逆転でパッチを開発・テストし、コミュニケーションを調整し、CVE を準備しながら、エクスプロイトが公衆に知られる前に業界パートナーと連携して防御策を実装しました。

その後

シルヴィー氏のブログ投稿では、脆弱な標的を対象として即座に警告する(そして有望な報酬を得る)ため、スキャンを開始した方法について記されています。攻撃者が武器化した場合の潜在的インパクトは壊滅的である可能性があります。大きな AI 企業から暗号取引プラットフォームまで、Next.js は非常に人気があり公開されています。

今後の投稿で、次の数日間の展開、「再現への競い合い」、0-day 保護という二刃の剣、そしてもちろん AI の関与について議論します。

同じ日のほかのニュース

一覧に戻る →

2026/05/09 3:45

グーグルによる再認証(reCAPTCHA)が、グーグルを利用しないアンドロイドユーザーにとって利用不能となりました。

## Japanese Translation: 元のサマリーは高品質ですが、以下の改善版では、「キーポイントリスト」に含まれていた特定の欠落していた詳細事項(Cloud Next の日程、iOS バージョン、具体的な期間)を統合し、提供されている粒度の事実と完全に整合させつつ、ナラティブの流れを維持しています。 ## 改善されたサマリー: Google は、次世代の reCAPTCHA システムを Android の Google Play Services と強く連携させることで、Google のプロプライエタリなソフトウェアを利用しないユーザーを実際に締め出す体制を確立しました。この変更により、疑わしい活動に対する従来の画像パズルが、QR コードのスキャンを要求し、これをトリガーとして Google サーバーとの背景通信を引き起こす仕組みに置き換えられました。iOS 16.4 以降を搭載した iOS デバイスはこれらの認証を追加アプリなしで完了できるのに対し、Android ユーザーは基本的なタスク(ヒューマン認証など)であっても特定の Play Services フレームワークバージョン(例:25.41.30)を実行させられています。インターネットアーカイブによる 2025 年 10 月のスナップショットを含む証拠から、この依存関係は公的な反発が発生するまで少なくとも 7 ヶ月間静かに構築されていたことが示唆されています。その結果、カスタム ROM を使用するユーザーや脱 Google化された電話機(例:GrapheneOS)を使用するユーザーは完全なアクセス拒否に直面しますが、iPhone ユーザーには影響がありません。これにより、重大なプライバシーの非対称性が生じ、基本的な Web コンテンツへのアクセスのために明示的に Google のインフラストラクチャと関与することを前提とする先例が確立されました。Google Cloud Fraud Defense(4 月 23 日の Cloud Next で発表されたもの)をこのシステムを採用するウェブ開発者は、結果として、Google のソフトウェアを回避するユーザーは歓迎されていないことを明確に示しており、プライバシー重視の個人の自由な閲覧能力を著しく制限することになります。

2026/05/08 2:11

OpenAI の WebRTC に関する問題

## Japanese Translation: OpenAI からの最近の技術ブログ投稿は、音声 AI アプリケーションにおける WebRTC の利用に関する強い批判を引き起こした。著者は以前 Twitch および Discord で勤務しており、WebRTC のリアルタイム遅延に固く設計された仕組み(特にブラウザ内でオーディオパケットの再送信ができず接続を断ちることなく破綻しないという点)が、不良ネットワーク条件下で音声 AI プロンプトの精度を大幅に低下させると論じている。テキスト読み上げストリーミングと異なり、WebRTC はバッファリング機構を持たず、高価な人為的なスリープ遅延を強制し、混雑中にパケット損失のリスクがある。さらに、WebRTC 内の TCP/TLS ハンブルク shakes は 2〜3 RTT を必要とし(シグナリング、ICE、DTLS、SCTP を含むと最大約 8 になる)、クライアント IP がネットワークスイッチングや NAT により変化すると直ちに失敗するため、OpenAI は STUN ステートをキャッシュするような脆弱なハックに依存している。Twitch や Discord のような業界リーダーは既に、プロトコルをフォークしたりネイティブアプリを使用したりすることで、これらの固有の欠陥を回避しており、多くの場合公式仕様に無視されている。一方、QUIC は Only 1 RTT の接続設定、唯一の受信者を選択した CONNECTION_ID を通じたステートレスなロードバランス(Redis の必要性を排除)、AnyCast と Unicast の両方へのサポートを提供する優れた代替案である。著者は、既存の TCP/HTTP インフラを利用し、Kubernetes 内でのシームレスなスケーリングを実現し、プロトコル上の制限と不要な遅延コストを排除することでユーザーエクスペリエンスを大幅に向上させるため、WebRTC を QUIC または WebTransport に置換することを推奨している。結局のところ、QUIC などの現代的なプロトコルを採用することで、企業は陳腐な制約と戦う代わりにサービスを効率的にスケールさせることができる。

2026/05/09 2:55

「人工知能が、二つの脆弱性文化を打破しています。」

## Japanese Translation: 核心的な主張は、現代の AI ツールがソフトウェアの脆弱性を瞬時に特定できるため、長期的なセキュリティ封鎖は危険なほど陳腐化しており、遅れた公開はユーザーおよび企業にとってリスクを伴うとすることである。従来の「調整された開示」の実践(バグを修正する前に数ヶ月間の待機期間を設けることが多くある)は、現在、人工知能を活用してほぼ直ちにエクスプロイトを見出す攻撃者にとって不必要に機会を与える窓を開いている。最近の事件から得られた証拠がこの転換を証明している;Hyunwoo Kim が公開したクリティカルなパッチは、別の研究者によって発見され、予定された長期的な封鎖を回避して公に共有された。これは、防衛側が現在、攻撃者が欠陥をスキャンするスピードと同等の速度で AI を使って検出・共有できるようになったことを示している。したがって、産業全体は特定モデルの比較(堅牢性に欠ける)に頼るのではなく、AI 駆動によるテストの高速化に合致するように開示スピードを見直し、非常に短い、あるいは封鎖を設けない方向へ移行すべきである。結局のところ、このより速いサイクルを採用することは、長期間の待機によって与えられる偽りのセキュリティ感を排除し、ユーザーが最近報告された ESP 脆弱性のようなこれまで見落とされていたギャップを自動化したスキャングループが武器化することを可能にする前に、クリティカルなパッチを受け取ることを確保する。

React2Shell シナリオ: * **文脈**: React フロントエンドアプリケーションとバックエンドシェルスクリプト環境の相互作用を描出した仮定の物語。 * **プロット**: ユーザーが React 経由でデータ可視化をリクエストすると、それに応じてシェルスクリプトによってバックエンドプロセスが実行され、人工データを生成した後に応答が行われる。 * **結末**: シェルスクリプトは出力を JSON 形式に整形し、React はそれをパースしてページ更新を行わずに動的に UI に描画する。 | そっか~ニュース