どうも、マイクでーす。おはようございます。
今日は2025年12月20日、土曜日の朝7時になりました。
ここからの時間は「zenncast」、最新のZennトレンド記事をゆるっと、でも中身はしっかりめに紹介していきます。通勤・通学中の方も、お休み満喫中の方も、よかったら最後までお付き合いください。

今日はね、セキュリティ寄りの話題から、UIライブラリ、TypeScriptのエラーハンドリングまで、エンジニア心をくすぐる記事がズラッと並んでます。
紹介する記事は全部で5本。ではさっそくいきましょう。

まず1本目。「Astroでreact2shellのような脆弱性が起きない理由」という記事です。
React / Next.js界隈をざわつかせたCVE-2025-55182、通称react2shell。RSC、つまりReact Server ComponentsのFlightプロトコル実装のバグや、複雑なリクエスト形式をちゃんと検証しきれてなかったこと、それからRSFという仕組みがクライアントとサーバーの境界をあいまいにした、いろんな要因が重なって「任意コード実行」という重めの問題につながったんですね。
この記事では、それと対比するかたちでAstroのServer Actionsを解説しています。ポイントは3つ。まず通信形式をJSONに限定して、Reactみたいな独自のバイナリっぽいプロトコルをやめているので、チャンクの解釈ミスとかプロトタイプ汚染の入り込みにくい設計になっていること。それから、Zodでスキーマを必須にして、サーバー側でバリデーションを強制している点。余計なプロパティも通しませんよ、というスタンスです。そして3つ目が、サーバー側のコードをsrc/actionsディレクトリに集約し、クライアントからはactions.xxxという明示的な呼び方をさせることで、RESTに近いシンプルなRPCとして「ここからサーバー」「ここからクライアント」という境界がはっきりしていること。
RSFみたいにバンドラ頼みの“魔法のようなRPC”ではなくて、「ボイラープレートを減らすけど、仕組みは読みやすく、安全寄り」という設計思想が、そもそも同種の脆弱性を起こしづらくしているんだ、という話でした。華やかな機能より、地に足ついた設計をどう選ぶか、という視点が参考になりますね。

。。。。

続いて2本目。「【OAuth】アクセストークンの検証を誤ると成りすまし攻撃ができます」。タイトルからして若干怖いですが、大事な内容です。
Auth0みたいなIDaaSを使って、SPA+バックエンドAPI構成を取るとき、フロントで取得したOAuthのアクセストークンを、そのままバックエンドへの“セッション代わり”として使うパターンって、結構ありますよね。この記事は、そのときの「アクセストークンの検証の甘さ」がどう成りすましにつながるかを丁寧に解説しています。
よくあるやらかしとして、JWTの署名が正しいかとか、iss、つまり発行者だけチェックして満足しちゃうケース。でも、本当に大事なのはaud、どのリソースサーバ向けのトークンなのか、そしてscope、このトークンで何が許されるのか、ここまで見ないとダメですよ、という話です。HonoのJWTミドルウェアでもaud検証がデフォルトでなくて、CVEをきっかけにオプションが追加された、という具体例も出てきます。ただし、そのオプションを“正しく設定する責任”は開発者側にあると。
さらに一歩踏み込んで、「そもそもアクセストークンをクライアントとサーバーのセッション代わりにする構成そのものが、OAuth本来の意図から外れていて脆弱化しやすい」という指摘もされていて、BFFパターンでバックエンドがクッキーを発行してセッション管理するほうを推奨しています。それでもアクセストークンを使う場合は、iss / aud / scopeの検証は必須、Opaqueトークンであっても発行元と対象はちゃんと確認しよう、と。
「とりあえずJWT通ればヨシ!」になりがちな人、耳が痛い内容かもしれませんが、実運用で本当に必要なチェックポイントが整理された良記事でした。

。。。。

3本目はちょっと雰囲気を変えてUIの話。「祝v1リリース、新たなヘッドレスUIライブラリBase UIが良さそう」という記事です。
React界隈で人気のヘッドレスUIといえばRadix UIが有名ですが、最近はメンテ頻度の低下が話題になっていて、「次の選択肢どうする?」という空気も出てきています。そんな中登場したのが、MUI Baseから独立してv1リリースされた「Base UI」。MUI、Radix UI、Floating UIの開発者も関わっているということで、かなり期待が高まっているライブラリです。
導入のハードルは意外と低くて、iOS 26以降のSafari対応としてbodyとrootへちょっとCSSを足すくらい。CSS Modules、Tailwindの両方に対応した豊富な実装例が用意されているのも嬉しいポイントです。特徴的なのは、RadixおなじみのasChildではなくRender functionのスタイルを取っているところで、これによって型安全性が高くなっていると。さらに、Autocomplete / Comboboxが標準対応しているので、実務でよくある検索UIなんかも作りやすい。タグ表示やuseFilterフックなんかも揃っていて、「コンポーネント自作するほどでもないけど、そこそこ複雑」という領域をうまくカバーしてくれそうです。
記事ではPopoverや、フォーム一式(Form / Field / Checkbox / Combobox)を組み合わせた検索フィルターフォームの実装例が紹介されていて、「あ、これ仕事でそのまま使えそう」という感触が伝わってきます。shadcn/createでもRadixかBase UIを選べる動きが出てきていて、今後のデファクト候補の一つとして要チェックですね。

。。。。

4本目はちょっとロマンのある話。「Deno に“守り”のコントリビュートしていたら、TC39 に出した言語仕様変更が承認され、ついでに V8 にパッチを投げた話」です。
筆者の方はDenoの内部コードを、プロトタイプ汚染などから守る“守りのコントリビュート”を続けてきた方。その過程で見つけたのが、String.prototype.splitなどの文字列メソッドが引数をRegExpかどうか判定するときの仕様の問題でした。ECMAScriptでは、引数にSymbol.splitが生えているかどうかで挙動を分岐するんですが、これを利用してString.prototype側にSymbol.splitを生やしてしまうと、任意の結果を返せてしまう、という危険な状況になっていたんですね。
そこで筆者は、「プリミティブ値にはRegExp用のWell-known Symbolメソッドを呼ばない」という方向でECMA-262へのノーマティブな仕様変更をTC39に提案します。これが会議で承認され、標準仕様として取り込まれることになりました。WebKitのJavaScriptCoreは他の方が実装を対応してくれた一方で、V8はまだだったので、なんと筆者自身がC++で修正パッチを書いて、レビューを受けて、最終的にChrome 143 / V8 14.3.106にマージされるところまでこぎつけます。その後、2025年12月10日にこの変更が正式にECMA-262へマージされた、というタイムライン。
「仕様って巨大組織が決めてるんでしょ?」というイメージに対して、実はこういう現場の開発者の問題意識と行動で一歩ずつ良くなっていくんだ、というエピソードです。SNSで文句を言うだけじゃなくて、適切な場所に報告したり、仕様や実装に貢献していこう、というメッセージで締めくくられていて、読んでいてすごく勇気が出る記事でした。

。。。。

そして最後、5本目。「try-catch に疲れたので、TypeScript で別の書き方を考えた」という記事です。
非同期処理が増えてくると、try-catchだらけのコード、見たことある人多いと思います。catchの中で型が失われたり、どこでエラーが握りつぶされてるのか追いにくかったり、ネストが深くなって読みづらくなったり…。この記事の筆者は、そうした問題に対して、GoやRustのような「エラーを値として扱う」発想をTypeScriptに持ち込んでいます。
TC39で議論中のSafe Assignment Operatorにも触れつつ、「TypeScriptではタプルよりDiscriminated Unionのほうが型安全だろう」という判断から、自作ライブラリ「try-ok」を開発。Result<T, E>という形で、成功と失敗をオブジェクトレベルで明示的に分けています。判別キーはisErrorで、これをチェックする前はdataとerrorの両方にアクセスさせない、チェックした後はどちらか片方だけが確実に存在する、というルールを型で保証する設計になっています。
これによって、「エラーをちゃんと扱い忘れる」「unknownのエラーと戦う」といったあるあるを防ぎつつ、React、特にRSCのような環境でも読みやすく安全なコードが書けるようになる、と提案しています。try-catchの海に溺れがちな人には、新しい設計のヒントになりそうな記事でした。

。。。。

というわけで、今日は5本の記事をご紹介しました。
Astroとreact2shell問題の対比から、OAuthアクセストークン検証の落とし穴、新しいヘッドレスUI「Base UI」の可能性、DenoからTC39・V8までつながる仕様貢献の物語、そしてTypeScriptでtry-catchから卒業するための設計アイデアまで、一気に駆け足でおさらいしましたが、気になるトピックはありましたでしょうか。

もっと詳しく読みたい方は、この番組のショーノートに元の記事の情報をまとめておきますので、そちらからぜひチェックしてみてください。
「zenncast」では、番組の感想や「こんなテーマ取り上げてほしい!」といったリクエストも大歓迎です。あなたの開発現場での悩みや、最近ハマっている技術の話なんかも聞かせてもらえると嬉しいです。

それでは今日はこのあたりで。
お相手はマイクでした。次回の「zenncast」でまたお会いしましょう。いってらっしゃい!

Related episodes

内容の近いエピソードを推薦しています