投稿者アーカイブ

WooCommerce 10.8リリース!レビューメール自動化と各種高速化の全容

WooCommerce 10.8リリース!レビューメール自動化と各種高速化の全容

WooCommerce 10.8が2026年5月26日にリリースされた。今回のアップデートでは購入後のカスタマーレビュー依頼メールの自動化、カスタム配送業者の設定機能、クーポンコードの動的生成、そして管理画面のパフォーマンス改善が盛り込まれている。

動作条件としてWordPress 6.9以上が必要だ。WooCommerceを更新する前にWordPress本体を最新にしておく必要がある。管理画面の一貫性を保つWordPress 7.0への事前適合も含まれており、今後のスムーズな移行に向けた布石となるリリースだ。

WooCommerce 10.8の主な変更点

WooCommerce 10.8の主な変更点

WordPress 7.0向けの管理画面スタイル調整

WooCommerce 10.8には約15件のプルリクエストが含まれ、WordPress 7.0の新しい管理画面デザインとの整合性を確保した。対象となったのはフォームコントロールのサイズ、Select2ドロップダウン、ボタンの角丸、通知の色、メタボックス周りのスタイルだ。

従来、WooCommerceの一部画面では青系の管理画面用色が直接ハードコーディングされていた。これがテーマカラー変数に置き換えられ、ユーザーが設定した配色スキームに沿って境界線やホバー状態が変化するようになった。WordPressとWooCommerceを同時に更新すれば、管理画面全体の見た目に統一感が出る。

従来の管理画面(Before)
ボタン ハードコーディングされた青色で固定表示
通知バー WordPress標準テーマ色に非対応
WooCommerce 10.8の管理画面(After)
ボタン テーマカラー変数を参照し自動で配色が変わる
通知バー 選択した管理画面テーマに追従

管理画面の色が選んだテーマに合わせて変化するため、複数サイトを運営している場合でもサイトごとに配色を変えられ、管理ミスの防止にもつながる。

オフライン対応の管理画面

WooCommerceの管理画面がオフラインを検知するようになった。ブラウザのネットワーク接続が切れるとバナーが表示され、保存リクエストがネットワーク喪失で失敗した場合には明確な通知が表示される。

これまで接続の不安定な環境では保存失敗に気づかず、注文データや設定の消失につながるケースもあった。モバイル回線やカフェのWi-Fiなど、接続状態が変わりやすい場所で作業するストア運営者にとっては実用的な改善だ。

従来の動作(Before)
保存ボタン押下 何も起こらない(失敗に気づかない)
10.8の動作(After)
オフラインバナー 「ネットワーク接続がありません」と画面に表示
保存失敗時 「保存に失敗しました」と通知が表示される

パフォーマンス改善の詳細

パフォーマンス改善の詳細

SQLクエリの削減と高速化

WooCommerce 10.7から続くクエリ削減の取り組みがさらに進んだ。取引IDルックアップ用の索引が wc_orders テーブルに追加され、販売ピーク時の在庫予約に使われる wc_reserved_stock テーブルの索引も改善された。

加えてキャッシュプライミングが商品アーカイブ、商品編集画面、クラシックカート、グループ化商品、Store APIの商品スキーマに拡張された。これにより各パスでデータを1行ずつ取得する代わりにバッチロードできるようになり、データベースへの負荷が大きく下がる。

クーポンの _used_by メタデータは遅延読み込み化された。何千回も使われたクーポンをロードする際に全使用履歴をメモリに展開しなくなり、クーポン読み込み時のパフォーマンスが飛躍的に改善する。レイヤードナビゲーションのフィルターキャッシュにはデフォルトで上限が設定され、wp_options テーブルが無制限に肥大化するのを防ぐ。

これまでのクーポン読み込み(Before)
_used_by メタ 全使用履歴を一度にメモリ展開(数千件で著しい遅延)
10.8の遅延読み込み(After)
_used_by メタ 必要なタイミングまで読み込みを遅延(メモリ節約)

ベータ版からの修正点

10.8のベータテスト期間中に見つかった問題も解消された。 WC_Order::payment_complete() に追加予定だったチェックアウト証跡のバリデーション機能は最終版から差し戻され、このリリースには含まれない。

また wc_orders_meta テーブルの meta_key_value 索引から meta_value 列が誤って削除されたパフォーマンス回帰も修正された。注文メタデータの検索速度が低下する問題だったが、10.8で索引構成が復元されている。

新機能の詳細

新機能の詳細

カスタマーレビュー依頼メールの自動化

10.8の目玉機能の一つが、購入者に商品レビューを依頼する自動メール機能だ。WooCommerceの設定の「メール」タブから有効化でき、Action Schedulerを使って注文完了から設定した日数後に送信される仕組みだ。

注文がキャンセル、返金、削除された場合にはメールは自動キャンセルされる。全額返金された商品はレビュー対象から外されるため、購入者と商品の関係が切れた状態でのレビュー投稿を防げる。顧客はトークン付きの専用読み取り専用ページに誘導され、アクセシブルな5つ星評価のコントロールからレビューを投稿する。投稿されたレビューは「確認済み購入者」の商品レビューとして扱われる。

従来のレビュー収集(Before)
ストア運営者 手動でレビュー依頼メールを作成・送信
課題 タイミングが属人的で管理が煩雑になる
10.8の自動レビュー依頼(After)
WooCommerce 注文完了から指定日数後に自動でメール送信
顧客 専用ページから5つ星評価+テキストレビューを投稿

この仕組みで集まったレビューは確認済み購入者の証跡が残るため、レビュー全体の信頼性を高められる。商品ページの社会的証明を強化したいストアには有効な手段だ。

クーポンコードの自動生成機能

メールブロック内で使えるクーポンコード機能が自動生成に対応した。ストア運営者は割引額やクーポンタイプ、有効期限といったルールを設定し、メール送信時に受信者ごとのユニークなコードを動的に発行できる。

パーソナライズされたクーポンキャンペーンの運用が大幅に簡略化される。全員に同じコードを配布して拡散リスクを抱える必要がなくなり、1人1コードの安全な配布が可能だ。

メールテンプレートの同期とリセット

ブロックメールの投稿にバージョン、ソースハッシュ、同期日時といったメタデータが付与されるようになった。テンプレートが元の配布状態からどれだけ変更されたかを自動検知できる。さらに管理画面からワンクリックでメール本文をプラグイン配布時のオリジナル状態に戻せるリセット機能も追加された。

カスタマイズを重ねたメールテンプレートの管理は煩雑になりがちだが、変更箇所の可視化と即時リセットで運用負荷が下がる。

カスタム配送業者の設定

独自の配送業者を定義できるUIが追加された。業者名と追跡URLテンプレートを登録すれば、注文画面で業者ごとのフィルタリングや、カスタマイズされた追跡リンクを使って出荷状況を確認できる。

国内の小規模な配送業者や地域限定の物流サービスを使っているストアでも、統一された画面から追跡情報を管理しやすくなる。

APIの更新

APIの更新

REST APIとGraphQL

注文APIでは shop_order でないレコードの変換が拒否されるようになり、チェックアウトドラフト注文はデフォルトクエリから除外されるようになった。より明示的なデータ操作が求められる変更だが、意図しないデータ混入を防ぐ点でAPIの堅牢性が増した。

注目すべきはGraphQL APIの導入だ。デュアルコードとGraphQL APIがWooCommerceに組み込まれ、管理画面の「詳細設定」タブにGraphQL設定セクションが追加された。GETエンドポイントのトグル操作で有効にできる。ヘッドレス構成やモダンなフロントエンドスタックからWooCommerceのデータを柔軟に取得したい開発者にとって重要な布石となる。

そのほか商品公開時に発火する product.published ウェブフックトピックの追加や、商品管理権限のないユーザーに対する機密フィールド(ダウンロード、売上原価、仕入メモ)の除外など、セキュリティ面の強化も図られている。

REST API(従来)
データ形式 エンドポイントごとに固定のレスポンス構造
課題 過剰取得や過少取得が発生しやすい
GraphQL API(10.8で導入)
データ形式 クライアントが必要なフィールドだけを指定
利点 通信量の削減とフロントエンド開発の効率化

データベースの更新と注意点

データベースの更新と注意点

このリリースにはデータベース更新が含まれている。自動実行されるスケジュール更新の中では、ブロックメール投稿への同期メタデータ付与、WooCommerce 10.5で名称変更された分析データのインポート設定復元、meta_key_value 索引の調整、レビュー依頼用の専用ランディングページ作成などが行われる。

10.8の更新前には必ずサイト全体のバックアップを取得し、ステージング環境での事前テストを推奨する。またWordPress 6.9以上が必須条件となるため、WordPress本体のバージョンも事前に確認しておく必要がある。

この記事のポイント

  • WooCommerce 10.8は購入後のレビュー依頼メールを自動化し、確認済み購入者のレビュー収集を効率化する
  • 管理画面のオフライン検知機能が追加され、ネットワーク不安定環境でのデータ消失リスクが低減した
  • クーポンコードの自動生成やメールテンプレートのリセット機能で運用負荷を下げられる
  • SQLクエリの削減とキャッシュプライミングの拡大により、ストアフロントの応答速度が向上する
  • GraphQL APIの導入はヘッドレス構成やモダンフロントエンド開発への対応を見据えた布石となる
海田 洋祐
DockerのCopy Fail脆弱性対応とseccomp破壊の教訓

DockerのCopy Fail脆弱性対応とseccomp破壊の教訓

2026年4月末に公開されたLinuxカーネルの脆弱性CVE-2026-31431、通称「Copy Fail」は、2017年以降のほぼ全てのカーネルに影響する深刻な問題だ。Docker社はこの脆弱性に対し、コンテナランタイムレベルでの緩和策を急ピッチで提供した。

その過程で、Docker Engine v29.4.2の修正が32ビットバイナリのネットワーク機能を完全に破壊するという予期せぬ副次的被害を引き起こした。本記事では、この一連の対応と教訓を技術的に深掘りする。

コンテナ運用者は、カーネルパッチの適用が最優先だが、それが叶わない場合でもDocker Engineのアップデートによりリスクを大幅に低減できる。ここで得られた知見は、今後のコンテナセキュリティ対策における多層防御の重要性を浮き彫りにしている。

Copy Fail脆弱性の仕組みとリスク

Copy Fail脆弱性の仕組みとリスク

AF_ALGサブシステムの欠陥

Copy Failは、Linuxカーネルの暗号処理をユーザー空間から利用するためのAF_ALG(Algorithm Sockets)サブシステムに存在する。具体的にはalgif_aeadモジュールの不具合により、特権のないプロセスがページキャッシュに対して不正な書き込みを行える状態になっていた。

ページキャッシュとは、ファイルの読み取りデータをメモリ上に一時保存する仕組みだ。全プロセスが参照するため、ここを汚染されると、システム全体でファイルの内容が改ざんされて見える可能性がある。最も直接的な攻撃経路は、setuidバイナリ(実行時に高い権限で動作するプログラム)の改ざんによる権限昇格である。

この脆弱性の深刻さは、その単純さにある。PoC(概念実証コード)はきわめて簡潔で、カーネルがパッチされていない限り、2017年以降のあらゆるバージョンで動作する。攻撃が成功すると、コンテナ内からホスト全体、そして同じノード上の他コンテナにまで影響が及ぶのだ。

脆弱性の悪用フロー(Before)
攻撃者 AF_ALGソケット作成 ページキャッシュ汚染 setuid改ざん root権限取得
※ デフォルトのコンテナ権限で実行可能。約7年にわたり影響。
緩和策適用後(After)
攻撃者 AF_ALGソケット作成 システムコールブロック
※ 多層防御によりAF_ALGへの経路が遮断される

このデモが示す通り、脆弱なカーネルでは攻撃者に一直線のルートを提供してしまう。Dockerの役割は、コンテナランタイムのレイヤーでこの経路を物理的に塞ぐことだった。

コンテナ環境への影響範囲

Dockerのデフォルトセキュリティプロファイルでは、コンテナからのAF_ALGソケット作成が許可されていた。つまり、攻撃者が何らかの方法でコンテナ内でコードを実行できた場合、この脆弱性を利用してホストのroot権限を奪取できる状態にあった。

さらに悪いことに、ページキャッシュはホスト全体で共有される。攻撃が成功した場合、被害はそのコンテナ内に留まらず、同じDockerイメージのレイヤーを共有する他のすべてのコンテナにも波及する。これは、マルチテナント環境やマイクロサービスを密に配置しているノードでは壊滅的な被害につながりかねない。

Docker Engineの対応と失敗の分析

Docker Engineの対応と失敗の分析

v29.4.2 seccomp修正の試み

Dockerチームは当初、seccomp(Secure Computing Mode / セキュアコンピューティングモード)プロファイルの更新で対応しようとした。seccompは、コンテナが発行できるシステムコールをフィルタリングする仕組みだ。具体的には、socket()システムコールの第一引数を検査し、AF_ALGアドレスファミリが指定された場合に拒否するルールを追加した。

しかし、x86_64 Linuxにはsocketcall()という古い多重化システムコールが存在する。これはsocket()bind()などの複数のソケット操作を一つのシステムコール番号の背後にまとめたものだ。問題は、socketcall()では実際の引数(アドレスファミリを含む)がユーザー空間の配列にパックされ、そのポインタが渡されることだ。seccompのフィルタエンジンであるBPFは、このポインタ先を参照して検査できない。

つまり、seccompだけではsocketcall()経由のAF_ALGを選択的にブロックできない。やむを得ずDockerチームは、socketcall()全体を拒否するという決断を下し、v29.4.2をリリースした。

v29.4.2でのブロック範囲(Bad)
socket(2) AF_ALG拒否 socketcall(2) 全体拒否
※ 32bitバイナリのネットワーク機能が破壊。SteamCMDやWineが動作不能に。
v29.4.3でのブロック範囲(Good)
AppArmor AF_ALG選択拒否 SELinux AF_ALG選択拒否 socketcall 許可(32bit互換性維持)
※ LSMを活用し、通常のネットワーク機能は維持したままAF_ALGだけを遮断。

この比較が示すのは、セキュリティ対策における粒度の重要性だ。全体をブロックすれば安全だが、システムの機能を破壊する。真に効果的な対策は、悪意のある操作だけをピンポイントで無効化することにある。

32bitバイナリ破壊の実態

socketcall()の一律拒否は、思わぬ大規模な副次的被害を引き起こした。32bit版のglibcは、すべてのソケット操作をsocketcall()経由で行う古いバージョンが残っている。Go言語のランタイムも、GOARCH=386でビルドされたバイナリでは無条件にsocketcall()を利用する。さらに、SteamCMDやWineといったレガシー・ゲーミング系のワークロードも、この仕組みに依存している。

これは単なるi386(32bit)の問題ではない。amd64環境であっても、プロセスはint $0x80命令を使うことでia32互換モードに切り替わり、直接socketcall()を呼び出せる。つまり、64bitのコンテナやバイナリを使っていても、この経路を利用される可能性があるのだ。

結果として、v29.4.2へのアップグレード後に多数の32bitアプリケーションがネットワークに接続できなくなるというインシデントが発生した(GitHub Issue: moby/moby#52506)。セキュリティパッチが新たな機能不全を引き起こすという、運用者にとって最も避けたいシナリオが現実となった。

根本原因:seccompの限界

この問題の本質は、seccompがシステムコール境界でのみ動作する点にある。socketcall()は一つのシステムコール番号の背後に多種の操作を隠蔽する。seccompのフィルタは、その中身である配列のポインタ先を解析できない。これが、seccomp単独では対応できない構造的な限界だ。

Dockerのブログ記事の著者は、「seccompはsocket(AF_ALG)をすべてのシステムでブロックするが、socketcall()に対しては盲目だ」と端的に表現している。この「見えない経路」の存在が、多層防御の必要性を強く示す教訓となった。

v29.4.3 LSMベースの恒久対策

v29.4.3 LSMベースの恒久対策

AppArmorとSELinuxによる多層防御

v29.4.3では、より根本的な解決策としてLinuxセキュリティモジュール(LSM)を活用する方針に切り替えた。AppArmorとSELinuxは、カーネル内部のsecurity_socket_create()コールバックに直接フックする。このコールバックは、socket()経由であれsocketcall()経由であれ、カーネルが実際にソケットオブジェクトを生成する瞬間に必ず呼ばれる。システムコールの入り口ではなく、より深いレベルで制御を行うのだ。

具体的な実装として、AppArmorプロファイルには deny network alg, というルールが追加された。これはAF_ALGアドレスファミリだけを対象に拒否する。SELinux環境向けには、すべてのcontainer_domainタイプに対してalg_socketの作成を拒否するCIL(Common Intermediate Language)ポリシーモジュールが提供され、semoduleコマンドでロード可能だ。

対策の全体像と適用優先度

v29.4.3の防御スタックは、以下の3層で構成されている。seccompによる直接のsocket(AF_ALG)ブロックは防御の一層目として維持しつつ、AppArmorまたはSELinuxによってsocketcall()経由の抜け道を塞ぐ。これにより、どちらか一方の防御層が無効化されても、もう一方がカバーする体制を実現した。

ただし、AppArmorやSELinuxはホストの設定に依存するため、LSMが有効化されていない環境ではsocketcall()経路が無防備なままとなる。この点については、依然としてカーネルパッチが唯一の完全な解決策であることに変わりはない。

STEP 1 Linuxディストリビューションのカーネルパッチを適用する
STEP 2 Docker Engineをv29.4.3以上にアップグレードする(再起動不要)
STEP 3 アップグレード不可ならカーネルモジュールをブラックリスト化する
STEP 4 それも不可ならカスタムseccompプロファイルを適用する

このステップを踏むことで、カーネルパッチの提供を待つ間のリスクを段階的に低減できる。最優先はカーネル修正だが、それが叶わない状況でもDocker Engineの更新だけで強固な緩和策となる。

コンテナセキュリティのための実践的教訓

コンテナセキュリティのための実践的教訓

ランタイム更新のスピードが生む防御力

Copy Failのケースで特筆すべきは、脆弱性の詳細が公表された時点で、主要ディストリビューションの多くはカーネルパッチを提供できていなかった点だ。Ubuntuは記事執筆時点で未対応であり、DebianやRHEL 9が対応を発表した段階だった。この数日間のギャップにおいて、コンテナランタイムの更新は唯一の実用的な緩和策だった。

コンテナ運用においてDocker Engineを最新に保つことは、単なる機能向上のためではない。カーネル脆弱性の公開からパッチ適用までの「空白期間」を埋める、最も迅速な防御手段の一つなのだ。

多層防御の絶対的必要性

このインシデントは「単一の防御層に頼ることの危険性」を端的に示した。seccompは強力だが、システムコールの粒度でしか制御できない。AppArmorやSELinuxはカーネル内部のオブジェクト生成にフックするため、より精密な制御が可能だが、ホストOSの設定に依存する。両者を組み合わせることで初めて、互いの死角を補完できる。

また、v29.4.2のsocketcall()拒否が引き起こした互換性問題は、セキュリティと互換性のトレードオフの難しさを教えている。広範なブロックは新たな問題を生む。可能な限りピンポイントな制御を追求し、やむを得ず広範な制限をかける場合は、その影響範囲を事前に十分評価する必要がある。

単層防御のリスク(Bad)
seccompのみ socket(2)ブロック socketcall()経由で突破
※ seccompはポインタ先を検査できず、抜け道を許す。
多層防御の有効性(Good)
seccomp socket(2)ブロック + AppArmor 両経路でAF_ALG拒否
※ カーネル内部フックにより、システムコールの種類を問わず遮断。

この比較から得られる教訓は明確だ。セキュリティ対策は、異なるレイヤーで相互に補完し合う設計が必須である。一つの仕組みで完璧を目指すのではなく、それぞれの得意領域を理解し、弱点を他の層でカバーする。これこそがコンテナセキュリティの基本原則である。

この記事のポイント

  • CVE-2026-31431はAF_ALGソケットを悪用し、2017年以降のLinuxカーネルに影響する
  • Docker v29.4.2のseccomp修正は32bitバイナリのネットワークを破壊する副次的被害を起こした
  • v29.4.3ではAppArmorとSELinuxを組み合わせた多層防御で選択的なAF_ALG遮断を実現
  • カーネルパッチが最も確実な修正だが、エンジン更新が迅速な緩和策として有効
  • 単一防御層の限界を認識し、複数の技術で死角を補完する設計が今後の鉄則となる
海田 洋祐
Vercel Sandboxの永続化機能が正式版に、環境構築の手間を大幅削減

Vercel Sandboxの永続化機能が正式版に、環境構築の手間を大幅削減

Vercelが提供するクラウド開発環境「Vercel Sandbox」において、filesystemの状態をセッション間で自動保存する永続化機能が正式版(GA)となった。2026年5月26日の発表だ。開発者はこれまで、Sandboxを再起動するたびに依存パッケージのインストールやファイル配置をやり直す必要があったが、今回のアップデートでその手間が大幅に削減される。

永続化はデフォルトで有効化されており、スナップショットの取得や状態管理を手動で行う必要はない。Sandboxに一意の名前を付与すれば、その名前をキーとして環境を再開できる仕組みだ。セッションの起動と停止はVercel側で自動的に処理されるため、開発者はワークフローを中断されることなく作業を継続できる。

Sandbox永続化が解決する課題

Sandbox永続化が解決する課題

クラウドベースの開発環境において、セッション終了後の状態消失は長年の課題だった。従来のVercel Sandboxでは、セッションが終了するたびにfilesystem上の全データが破棄されていた。このため、毎回の起動時に再度依存関係のインストールや環境設定を行う必要があり、開発開始までの待ち時間が大きな非効率を生んでいた。

永続化機能は、この問題に対する直接的な解決策だ。Sandboxのfilesystem状態が自動的にスナップショットとして保存され、次回セッション開始時に自動復元される。スナップショットはユーザーが明示的に操作する必要はなく、セッション終了時に自動取得される仕組みである。これにより、npmパッケージのインストールやプロジェクトファイルの配置といった繰り返し作業から開発者が解放される。

従来のSandbox(Before)
起動 npm install ファイル配置 開発開始

※毎回セッション開始時に環境構築が必要。待ち時間が発生し、開発効率が低下する

永続化対応後(After)
起動 自動復元 即座に開発開始

※前回の状態が自動的に復元される。セットアップ不要で作業を継続できる

この変化は、継続的な開発やCI/CDパイプラインでの自動テストなど、頻繁な環境再作成が発生するシナリオで特に効果を発揮する。

永続的Sandboxの作成と利用

永続的Sandboxの作成と利用

デフォルトで有効化される永続性

Sandbox.create()を呼び出す際、永続化は自動的に有効になる。特別な設定やオプションの指定は不要だ。作成時にnameパラメータで一意の名前を付与すれば、その名前がプロジェクト内での参照キーとなる。この名前は後から変更することも可能であり、プロジェクトの命名規則に合わせた管理ができる。

名前付きSandboxは単なる識別子以上の役割を持つ。チーム内で「staging-test」「feature-auth」といった意味のある名前を付けることで、目的に応じた環境の使い分けが容易になる。また、存在しない名前を指定した場合は新規作成、既存の名前を指定した場合は既存環境の復元と、名前ベースの直感的な操作が可能だ。

import { Sandbox } from "@vercel/sandbox";

// filesystemは自動的にスナップショット保存される
const sandbox = await Sandbox.create({ name: "my-sandbox" });

await sandbox.runCommand("npm", ["install"]);

await sandbox.stop();

上記のコードでは、npm installでインストールされた依存パッケージが自動的にスナップショットとして保存される。次回Sandbox.get({ name: "my-sandbox" })で取得した際には、インストール済みの状態から即座に作業を再開できる。

ステートレスSandboxとの使い分け

永続化は便利だが、すべてのユースケースで必要とは限らない。一時的な検証や使い捨てのテスト環境では、永続化を無効にすることでスナップショット保存にかかるストレージコストを節約できる。スナップショットストレージはコンピューティングリソースとは別の課金体系であり、不要な保存はコスト増につながるためだ。

import { Sandbox } from "@vercel/sandbox";

const sandbox = await Sandbox.create({ persistent: false });

// 既存のSandboxを後から変更することも可能
await sandbox.update({ persistent: false });

CLIを利用する場合は、sandbox createコマンドに--non-persistentフラグを付与する。非永続的Sandboxはセッション終了時にfilesystemが完全に破棄されるため、機密データを含む一時的なテストや、毎回クリーンな状態から始めたいCIジョブに適している。

永続的Sandboxと非永続的Sandboxの比較
永続的Sandbox
継続的な開発環境
チーム共有の検証環境
長期メンテナンスのテスト環境
非永続的Sandbox
使い捨てのコード検証
クリーン状態が必要なCIジョブ
機密データを含む一時テスト

この使い分けにより、必要な場面では永続化の利便性を享受しつつ、不要な場面ではコストを最適化できる。開発の初期段階で「この環境は使い続けるか、それとも一度限りか」を判断基準にするのが実践的なアプローチだ。

セッション再開の仕組み

セッション再開の仕組み

永続化されたSandboxの再開は完全に自動化されている。停止中のSandboxに対してrunCommand()writeFiles()などの操作を呼び出すと、最新のスナップショットから自動的に新しいセッションが開始される。開発者が明示的に「再開」を指示する必要はなく、操作の実行がトリガーとなって透過的に処理される。

import { Sandbox } from "@vercel/sandbox";

const resumedSandbox = await Sandbox.get({ name: "my-sandbox" });

// 自動的にSandboxが再開される
await resumedSandbox.runCommand("npm", ["test"]);

Sandbox.get()で取得した段階ではまだセッションは開始されておらず、実際にコマンドを実行するタイミングでバックグラウンドで復元処理が走る。この遅延実行モデルにより、不要なセッション起動を避け、リソースの効率的な利用が可能になる。復元にかかる時間はスナップショットのサイズに依存するが、一般的なプロジェクト規模であれば数秒から十数秒程度で完了する。

Sandbox再開の内部フロー
STEP 1 Sandbox.get({ name: “my-sandbox” }) で参照を取得(まだ起動しない)
STEP 2 runCommand() 等の操作が呼び出される
STEP 3 バックグラウンドでスナップショットからfilesystemを復元
STEP 4 コマンド実行・ファイル書き込みが通常通り処理される
※復元は透過的に行われ、開発者は「再開」を意識する必要はない

この設計の利点は、開発者が環境のライフサイクル管理から解放される点にある。「今このSandboxは起動しているか」「停止状態からどう再開するか」といった状態管理の認知負荷がなくなり、コードの記述やテストの実行といった本質的な作業に集中できる。

コスト管理とスナップショットストレージの最適化

コスト管理とスナップショットストレージの最適化

永続化機能の利用にあたって注意すべき点は、スナップショットストレージの課金だ。Vercel Sandboxの料金体系では、コンピューティングリソースとスナップショットストレージが別々に課金される。永続化を有効にしたSandboxが増えるほど、保存されるスナップショットの総容量も増加し、それに比例してコストが発生する。

では、どのようにコストを最適化すればよいのか。以下の方針が実践的だ。

スナップショットコスト最適化の判断基準
永続化すべきケース
同じ環境を週に3回以上起動する
npm install に30秒以上かかる大規模プロジェクト
チームメンバー間で共有する標準環境
非永続化が適切なケース
一度限りのバグ再現テスト
PRごとに自動生成されるCI環境
依存関係がほぼない小規模スクリプトの実行

実際の運用では、Sandbox.update({ persistent: false })を使って後から設定を切り替えられるため、最初は永続化ありで作成し、不要と判断した時点で無効化する柔軟な運用が可能だ。また、Sandbox.delete()を使えば不要になったSandboxとそのスナップショットを完全に削除でき、ストレージの無駄遣いを防げる。

スナップショットの保存間隔や保持数については、現時点ではセッション終了時に自動取得される仕組みのみが提供されている。将来的にはスナップショット取得のタイミングを制御するオプションが追加される可能性もあるが、現行バージョンではシンプルに「停止時保存」のモデルで統一されている。このシンプルさが、開発者の意思決定コストを下げている面もある。

その他の重要な改善点

その他の重要な改善点

今回のGAリリースでは、永続化機能に加えていくつかの重要なAPI拡張も同時に提供されている。これらは永続化機能と組み合わせることで、より柔軟なSandbox管理を実現する。

Sandbox.fork() による環境の複製

既存のSandboxから新しいSandboxを作成するSandbox.fork()が追加された。特定の時点の環境を複製し、そこから別の検証を分岐させたいケースで役立つ。たとえば、メインの開発環境から「機能Aの実験用」「機能Bの実験用」をそれぞれフォークし、独立してテストを進められる。

Sandbox.getOrCreate() の冪等性

Sandbox.getOrCreate()は、指定した名前のSandboxが存在すれば取得し、存在しなければ新規作成する冪等な操作を提供する。CI/CDパイプラインでの環境セットアップスクリプトなど、「あれば使う、なければ作る」というパターンが1行で完結する。エラーハンドリングの分岐を書く必要がなくなり、コードの可読性が向上する。

ライフサイクルフックとタグ機能

onCreateおよびonResumeフックが追加され、Sandboxの作成時や再開時に任意の処理を挿入できるようになった。環境変数の動的設定や、起動時チェックの自動実行など、プロジェクト固有の初期化処理を組み込める。また、Tags機能によりSandboxにカスタムプロパティを付与でき、マルチテナント環境での追跡や分類が容易になる。たとえば「environment: staging」「team: frontend」といったタグを付けてフィルタリングすることが可能だ。

実践的な活用シナリオ

実践的な活用シナリオ

永続化機能の登場により、Vercel Sandboxの適用範囲は大きく広がる。ここでは具体的な活用シナリオをいくつか挙げる。

チーム内の共通開発環境として

すべての依存パッケージがインストール済みのSandboxをSandbox.fork()でメンバーに配布。環境構築の時間をゼロにし、全員が同一条件で開発を始められる。新メンバーのオンボーディング時間も大幅に短縮される。

CI/CDパイプラインの高速化

テストスイートの実行環境を永続化し、依存パッケージのインストール時間を削減。PRごとにSandbox.getOrCreate()で専用環境を用意し、テスト実行後のクリーンアップもSandbox.delete()で自動化できる。

バグ再現と修正検証

報告されたバグの発生環境をSandboxで再現し、そのまま永続化。修正パッチの検証が完了するまで環境を保持し、必要に応じてSandbox.fork()で別の修正アプローチも並行テストできる。

これらのシナリオに共通する利点は、「環境の再現性」と「セットアップ時間のゼロ化」だ。特にマイクロサービスアーキテクチャのように複数の依存関係が絡むプロジェクトでは、個々の開発者がローカルで依存関係を解決するよりも、クラウド上の永続化環境を共有する方が圧倒的に効率的なケースが多い。

この記事のポイント

  • Vercel Sandboxの永続化機能が正式版となり、セッション間のfilesystem自動保存がデフォルトで有効化された
  • 名前ベースのSandbox管理で環境の作成・取得・再開が直感的に行え、スナップショット操作は完全自動化されている
  • 永続的Sandboxと非永続的Sandboxの使い分けにより、利便性とコスト最適化のバランスが取れる
  • forkやgetOrCreateなどのAPI拡張で、チーム開発やCI/CDパイプラインへの統合がより容易になった
海田 洋祐
Supabaseプロジェクトをnpmサプライチェーン攻撃から守る7つの防御策

Supabaseプロジェクトをnpmサプライチェーン攻撃から守る7つの防御策

npmエコシステムを狙ったサプライチェーン攻撃が2026年に相次いでいる。5月には、TanStackがGitHub Actionsのワークフローキャッシュを汚染され、正規リリースに悪意あるコードが混入する事件が発生した。Supabaseも同様に、supabase-javascriptというタイポスクワット(入力ミスを狙った偽装パッケージ)がnpm上に現れるなどの標的に遭っている。

同社はこの事態を受け、プロジェクトの保護に向けた社内横断の対応を開始し、誰もが参照できる公式ガイドを公開した。本記事では、そのガイドの中核を抜粋し、攻撃の構造と開発者が今すぐ実施すべき防御策を具体的に解説する。

npmサプライチェーン攻撃の3つの典型的な手口

npmサプライチェーン攻撃の3つの典型的な手口

サプライチェーン攻撃は、直接システムに侵入するのではなく、開発者が信頼しているパッケージに悪意あるコードを忍び込ませる。以下が最も一般的な三つの手口だ。

メンテナの認証情報を奪う「アカウント乗っ取り型」

攻撃者がnpmの公開トークンを盗むか、メンテナをフィッシングして乗っ取り、人気パッケージの新版に悪意あるコードを仕込んで公開する。次にnpm installを実行すると、その悪質なバージョンが導入されてしまう。

入力ミスを誘う「タイポスクワッティング型」

本物のパッケージ名から数文字だけ変えた類似名でパッケージを登録し、開発者やAIコーディングエージェントが誤ってインストールするのを待つ。Supabaseの例では、@supabase/supabase-js ではなく supabase-javascript というスコープなしの名前で公開された。AIエージェントがパッケージ名を幻覚(ハルシネーション)して提案することも多く、この手法は脆弱だ。

ビルドパイプラインを悪用する「CI/CD侵害型」

この手口は、GitHub ActionsなどのCI/CDパイプラインの脆弱なワークフローを突く。攻撃者はフォークしたプルリクエストからワークフローのキャッシュを汚染し、次回の正規リリース実行時にそのキャッシュを拾わせて、正規メンテナの署名で悪意あるコードを公開させる。TanStackを襲った攻撃がまさにこれで、セッションメッセンジャーネットワーク経由で機密情報が流出した。

アカウント乗っ取り型
攻撃者がメンテナ権限を奪い、正規パッケージに悪意あるコードを仕込んで公開
タイポスクワッティング型
類似名の偽パッケージを登録し、開発者の打ち間違いやAIの誤提案を誘う
CI/CD侵害型
ビルドパイプラインのキャッシュを汚染し、正規リリースに紛れて悪質なコードが配布される

いずれの手口も、npm install の完了までに環境変数やAWSメタデータ、SSH秘密鍵といった機密情報を根こそぎ奪われる危険がある。

Supabaseが実施するプロジェクト防御策

Supabaseが実施するプロジェクト防御策

Supabaseはこの問題に対し、全社的な対応を開始した。以下が現在進行中の主な取り組みである。

公式セキュリティガイドの公開

同社は、npmセキュリティに関する推奨事項をまとめた単一の正規ガイドページを公開した。エージェントが読み取り可能な形式で、具体的なアクションを指示している。

GitHub Actionsの安全性強化

組織全体で pull_request_target の使用を精査し、アクションのバージョン参照をコミットSHAに固定する強制ルールの適用が最終段階に入っている。

クレデンシャル関連APIへの警告注釈

createClient などの関数にTSDoc(TypeScript向けドキュメントコメント)を追加し、エディタ上でホバー時に機密情報を扱う旨の警告が表示されるようにした。

全チャネルでの啓蒙活動

顧客かどうかを問わず、できるだけ多くの開発者に防御策を届けるため、ブログやコミュニティを通じた情報発信を強化している。

依存関係管理の厳格化

依存関係管理の厳格化

以下に挙げる設定変更は、いずれも数分で完了する。どれか一つでは完全な防御にはならないが、複数積み重ねることで攻撃者が諦めるほどの障壁を築ける。

パッケージマネージャを最新にして公開遅延を設定する

pnpm 11(またはnpm v11相当)にアップグレードし、minimumReleaseAge をデフォルトの24時間より長く設定する。多くの悪意あるパッケージはリリース後24〜48時間以内に検出され削除されるため、3〜7日の遅延を設けると、被害を受ける確率を大幅に下げられる。

# pnpm-workspace.yaml または .npmrc
minimumReleaseAge: 4320  # 分単位、3日

依存バージョンを固定する

^~ による範囲指定は、npmに対して「次のマイナーやパッチを自動的に取り入れて問題ない」と伝えているに等しい。認証情報やネットワーク通信を扱うパッケージでは、必ず正確なバージョン番号を指定しよう。

従来のバージョン指定(Before)
"dependencies": {
  "@supabase/supabase-js": "^2.39.0",
  "axios": "~1.6.0"
}
防御策適用後(After)
"dependencies": {
  "@supabase/supabase-js": "2.39.0",
  "axios": "1.6.2"
}

ロックファイルをコミットし差分を精査する

pnpm-lock.yamlpackage-lock.json は、インストールされた正確なバージョンとハッシュを記録する。攻撃者が同じバージョン番号で悪意あるtarballを差し替えても、ハッシュが一致せずインストールが失敗する。ロックファイルをリポジトリにコミットし、プルリクエストの差分では目的不明な依存関係の変更がないか必ず確認する。

不用なインストールスクリプトを無効化する

サプライチェーン攻撃のペイロードの多くは、preinstall install postinstall といったライフサイクルスクリプトを通じて実行される。ネイティブコードを含むパッケージを必要としないプロジェクトでは、これらをグローバルに無効化する。npmでは npm config set ignore-scripts true または .npmrcignore-scripts=true を記述する。pnpmではAllow Buildsモデルを使って、実際に必要なパッケージだけを許可リストに登録する。

安全なパッケージ導入のための実践

安全なパッケージ導入のための実践

パッケージ名を毎回検証する

タイポスクワッティング対策として、以下の点をインストール前に必ず確認する。

  • スコープが正しいか。Supabase公式パッケージはすべて @supabase/ 配下にある。
  • メンテナの一覧が期待通りか。長年維持されてきたパッケージに新しいメンテナが突然加わっていれば警戒信号だ。
  • ダウンロード数とリンク先のGitHubリポジトリが、本物のパッケージとして妥当であること。

CI/CDワークフローを狙った攻撃への対策

CI/CDワークフローを狙った攻撃への対策

ActionsをコミットSHAで固定する

ワークフローで参照するサードパーティアクションは、タグではなくコミットの完全なSHAハッシュ(40文字)で固定する。タグは攻撃者が新しいコードで置き換えられるため安全でない。

- uses: actions/checkout@1f9a0c22da41e6ebfa534300ef656b67ce0c5b94 # v6.0.2

pull_request_target の危険な使い方を回避する

pull_request_target イベントは、プルリクエストのコードをチェックアウトして実行するコンテキストで使うと、攻撃者がリポジトリのシークレットやキャッシュにアクセスできてしまう。TanStackを襲った攻撃はまさにこのパターンだった。PRのコードに触れる処理は必ず pull_request を使用し、pull_request_target はラベリングやコメント投稿など、コードを実行しない信頼済み操作に限定する。

危険なワークフロー(Bad)
on:
  pull_request_target:
    types: [opened, synchronize]
jobs:
  build:
    - uses: actions/checkout@v4
      with:
        ref: ${{ github.event.pull_request.head.sha }}
安全なワークフロー(Good)
on:
  pull_request:
    types: [opened, synchronize]
jobs:
  build:
    - uses: actions/checkout@v4

インシデント発生時の即応策

インシデント発生時の即応策

クレデンシャルのローテーションと監査

もし疑わしいパッケージを含む環境で npm install を実行してしまったら、そのマシンを危殆化したと見なし、到達可能なすべての認証情報(AWS、GCP、Kubernetes、Vault、GitHub、npm、SSH、Supabaseのサービスロールキー)を直ちにローテーションする。Supabaseのダッシュボードでサービスロールキーの使用状況を監査し、不審なアクセスパターンがないかも確認する。半日はかかる作業だが、顧客への被害を防ぐ価値は十分にある。

スキャナの導入で第二の防御線を

Socket.devやnpq、Snykといったツールは、npmレジストリのパッケージをリアルタイムで監視し、怪しい挙動をフラグ付けしてくれる。これらは万能ではないが、基本的な対策をすでに実施しているチームにとって有効な第二の防御線となる。

AIコーディングエージェントに渡すセキュリティチェックリスト

AIコーディングエージェントに渡すセキュリティチェックリスト

以下は、Supabaseが推奨するリポジトリ監査プロンプトだ。Claude CodeやCursorなどに貼り付け、変更内容を必ず確認しながら適用する。プッシュやPR作成、依存関係の自動追加、クレデンシャルのローテーションは自動化せず、必ず人間が承認する。


このリポジトリのnpmサプライチェーン衛生状態を監査してください。以下の変更を適用し、何を行ったかを報告してください。明示的な承認なしにプッシュ、PR作成、新しい依存関係のインストール、クレデンシャルのローテーションは行わないでください。

パッケージマネージャ:
- 古いバージョンならpnpm 11+(または最新のyarn/npm/bun)にアップグレード
- 新バージョンに7日間の公開遅延を設定
  - pnpm: `minimumReleaseAge: 10080` を pnpm-workspace.yamlに
  - npm: `min-release-age=7` を .npmrcに
  - yarn (berry): `npmMinimalAgeGate: '7d'` を .yarnrc.ymlに
  - bun: `minimumReleaseAge = 604800` を bunfig.tomlの[install]セクションに
- ライフサイクルスクリプトをデフォルトで無効化。pnpmではallowBuildsで明示的に許可するパッケージをリスト。
- 非レジストリの透過的依存参照をブロック。pnpmでは`blockExoticSubdeps: true`等を設定。
- パッケージマネージャ自体を正確なバージョンとsha512ハッシュで固定

ロックファイルと依存関係:
- ロックファイルがコミットされていることを確認(gitignoreされていない)
- 認証、シークレット、通信、暗号、ユーザデータを扱う依存関係では^/~を正確なバージョンに置き換え
- Supabase関連のインポートがすべて`@supabase/`スコープか検証。スコープなしの類似名はタイポスクワットとしてフラグ

GitHub Actions(存在する場合):
- すべてのサードパーティアクションのusesを40文字のコミットSHAに固定し、元タグをコメントで残す
- pull_request_targetを使いPRコードをチェックアウトしているワークフローを抽出し、pull_requestへの書き換えを提案
- インストールワークフローに`npm audit signatures`の非ブロッキングステップを追加

人の確認が必要な項目:
- Dependabotアラートとシークレットスキャンが無効なら有効化を提案

レポート:
- ファイル変更ごとに1行の理由付きリスト
- 自動変更せずに人の判断が必要な項目の一覧

この記事のポイント

  • npmサプライチェーン攻撃は、アカウント乗っ取り、タイポスクワッティング、CI/CD侵害の3パターンに大別される
  • Supabaseは公式ガイド公開、GitHub Actions強化、API警告追加などで対策を推進中
  • 即効性のある防御策として、パッケージマネージャの更新と公開遅延設定、バージョン固定、ロックファイル精査、インストールスクリプト無効化、パッケージ名検証、ActionsのSHA固定、pull_request_targetの回避がある
  • 万が一侵害が疑われる場合はクレデンシャル全ローテーションとスキャナ導入で二次被害を防ぐ
  • AIエージェントには安全な監査プロンプトを組み込み、自動変更を人の目でレビューする体制を整える
海田 洋祐
View Transitions、大量要素スケーリングにview-transition-classが効く

View Transitions、大量要素スケーリングにview-transition-classが効く

クロスドキュメントビュートランジション(View Transitions)は、ページ間の遷移をアプリのように滑らかにする強力なAPIだ。しかし本番環境で数十、数百の要素を扱おうとすると、途端にスケーリングの問題に直面する。1つのヒーロー画像を動かすデモは簡単だが、48枚の商品カードを個別に遷移させるとなると話が違う。

本記事では、view-transition-classと動的な名前付けの手法を用いて、大量要素を効率よく扱う方法を解説する。CSS-Tricksで公開された連載Part 2の内容を基に、実践的なパターンとアクセシビリティへの配慮までカバーする。

view-transition-classがスケーリングの鍵

view-transition-classがスケーリングの鍵

多くのチュートリアルでは、1つの要素にview-transition-name: heroを付与し、ページ間でマッチさせる。しかし実際のプロダクトグリッドでは、48枚のカードには48の一意な名前が必要になる。CSSでこれに対応しようとすると、次のような悪夢が待っている。

::view-transition-group(card-1),
::view-transition-group(card-2),
::view-transition-group(card-3),
::view-transition-group(card-4),
::view-transition-group(card-5),
::view-transition-group(card-6),
::view-transition-group(card-7),
::view-transition-group(card-8)
/* ... さらに92個続く */ {
  animation-duration: 0.35s;
  animation-timing-function: ease-out;
}

この方法は、要素数が増えるほど管理不能になる。100個の商品があれば100個のセレクタを書かなければならず、保守は事実上不可能だ。

名前とクラスの決定的な違い

ここで重要になるのが、view-transition-nameview-transition-classの使い分けだ。両者は似ているようで役割がまったく異なる。

  • nameは「同一性」を表す。ページAのサムネールとページBのヒーロー画像が「同じもの」だとブラウザに伝える。nameはページ内で一意でなければならない。重複するとトランジションは破棄される。
  • classは「スタイルのフック」だ。50の要素がview-transition-class: cardを持てば、1つのCSSルールでそれらすべてのアニメーションを制御できる。通常のCSSクラスと同じ考え方で、特定の要素を指すものではなく「こう見せたい」をグループ化する。

データベースにたとえるなら、nameが主キー、classがカテゴリ列に相当する。主キーは一意に1行を特定し、カテゴリ列はまとめてクエリをかけるために使う。

クラスを使った共通スタイルの記述

実際のCSSはこうなる。6枚のカードに6つのユニークなnameを与えつつ、アニメーションのルールはたった3つで済む。

::view-transition-group(*.card) {
  animation-duration: 0.35s;
  animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

::view-transition-old(*.card),
::view-transition-new(*.card) {
  object-fit: cover;
}

セレクタの*.cardは「view-transition-classがcardであるすべてのビュートランジショングループ」を意味する。アスタリスクはnameのワイルドカードで、classにマッチする。これでカードが60枚でも600枚でもCSSは変わらない。

従来手法(各カードに個別セレクタ)
48個のカードそれぞれに固有のルールを記述する必要がある
::view-transition-group(card-1), ::view-transition-group(card-2), …
※ 100個を超えると事実上管理不能
view-transition-class を使った改善後
共通クラスに1つのルールを書くだけ
::view-transition-group(*.card) { animation-duration: 0.35s; }
※ 何枚でもCSSは変わらない
■ 要素数に依存せず、わずか数行で全カードのアニメーションを制御できる

このように、view-transition-classは大量要素のビュートランジションにおける、スケーリングの本質的な解決策だ。CSSのみで記述する理想形であるident("card-" sibling-index())のような自動生成はまだブラウザに実装されていないが、クラスを使えば十分なスケールを得られる。

動的名前付けでパフォーマンスを最適化

動的名前付けでパフォーマンスを最適化

view-transition-classでスタイルのスケーリングは解決した。しかし、nameをページロード時にすべて付与してしまうと、別の問題が発生する。ユーザーが1枚のカードをクリックするだけでも、ページ上の全カード(48枚)のスナップショットが撮られ、疑似要素ツリーが構築されてしまうのだ。これは余計なコストであり、特にミドルレンジのモバイル端末ではトランジションのカクつきやスキップを引き起こす。

pageswapとpagerevealのライフサイクル

正しいアプローチは、nameを「ジャストインタイム」で付与することだ。ユーザーが操作したその瞬間にだけnameを設定し、遷移が終われば削除する。これにより、実際に遷移する要素だけがキャプチャされ、無駄な処理が発生しない。

流れはこうだ。

  • ユーザーが一覧ページでカードをクリックする。
  • ブラウザがナビゲーションを開始し、旧ページでpageswapイベントが発火する。
  • pageswapハンドラがクリックされたカードを特定し、view-transition-name: product-42を動的にセットする。
  • ブラウザがその要素のスナップショットを撮る。
  • 新ページが読み込まれ、pagerevealイベントが発火する。
  • pagerevealハンドラがURLからIDを読み取り、ヒーロー要素に一致するnameを割り当てる。
  • ブラウザが新旧のスナップショットをマッチさせ、モーフィングアニメーションを再生。
  • トランジションが完了したら、viewTransition.finishedのPromise解決後にnameをクリアする。

この一連の流れで、名付けられるのはたった1つの要素だけだ。48枚のカードのうち47枚は何も関与せず、無駄なスナップショットはゼロになる。

商品一覧ページ(クリック前)
カード42 data-id=”product-42″(name未設定)
ページロード時は全カードが匿名
↓ クリック
pageswap イベント発火
JavaScriptが view-transition-name: product-42 を動的に付与
↓ スナップショット → 遷移
商品詳細ページ
ヒーロー画像 pagereveal で view-transition-name: product-42 を設定
名前が一致し、モーフィング開始
■ クリックされた1要素だけがトランジションに参加し、残りは無視される

このパターンは、Astroのtransition:nameディレクティブやNuxtのビュートランジションサポートが内部的に行っていることと本質的に同じだ。フレームワークが抽象化している処理を、pageswappagerevealで直接制御していると考えればよい。

名前のクリーンアップが重要な理由

トランジション完了後にnameを削除するステップは、単なるお片付けではない。もしユーザーが一覧ページに戻り、別のカードをクリックした場合、古いnameが残っていると重複によるエラー(トランジションが即時破棄される)か、誤った要素とのマッチングが起きる。必ずviewTransition.finishedの解決後にnameをクリアすること。

実践的なパターン集

実践的なパターン集

商品グリッド以外にも、いくつかの典型的なパターンが存在する。実際のサイトで遭遇する状況に合わせて応用できる。

アスペクト比混合のフォトギャラリー

サムネールと拡大画像でアスペクト比が異なるギャラリーは、object-fit: coverで歪みを防ぎつつ、クラスで統一的に制御する。ポイントは、view-transition-name<img>自身に付与し、カードの枠やキャプションを含めないことだ。画像だけをモーフィングさせ、背景や枠は別のトランジションとして扱う。

::view-transition-group(*.gallery-item) {
  animation-duration: 0.5s;
  animation-timing-function: cubic-bezier(0.2, 0, 0, 1);
}

::view-transition-old(*.gallery-item),
::view-transition-new(*.gallery-item) {
  object-fit: cover;
  overflow: hidden;
}

/* ライトボックス背景は別クラスでフェード */
::view-transition-group(*.lightbox-bg) {
  animation-duration: 0.3s;
}

ライトボックスの暗いオーバーレイには、別のnameとclassを与え、独立したフェードインアニメーションを適用する。画像のモーフィングと背景のフェードが並行して走り、洗練された印象になる。

タブやセクションの切り替え

ダッシュボードタブやマルチステップフォームなど、同一ページ内でのセクション遷移にも同じ手法が使える。固定ヘッダーにはanimation-duration: 0sを指定して「動かない」ようにし、コンテンツだけがスライドする感覚を出す。

::view-transition-group(*.persistent) {
  animation-duration: 0s; /* 動かさない */
}

::view-transition-group(*.tab-content) {
  animation-duration: 0.25s;
}

::view-transition-old(*.tab-content) {
  animation: slide-out-left 0.25s ease-in;
}

::view-transition-new(*.tab-content) {
  animation: slide-in-right 0.25s ease-out;
}

永続的な要素にアニメーションをかけないことで、UI全体に安定感が生まれる。

無限スクロールと動的コンテンツ

無限スクロールで後からDOMに追加された要素にも、特別な対応は不要だ。pageswapハンドラはナビゲーション発生時にDOMをクエリする。要素がその時点で存在していれば、問題なくnameを割り当てられる。唯一注意すべきは、data-idなどマッチングに使う識別子が動的に追加されたバッチ間でも一意であることだ。APIが返すIDを利用していれば問題ない。

アクセシビリティとprefers-reduced-motion

アクセシビリティとprefers-reduced-motion

アニメーションは、前庭障害を持つユーザーに吐き気やめまい、片頭痛を引き起こす可能性がある。prefers-reduced-motionメディアクエリは、OSレベルで「動きを減らしてほしい」と設定しているユーザーを検出する。ビュートランジションを導入するなら、この対応は必須だ。

@view-transition {
  navigation: auto;
}

/* アニメーションのカスタマイズはすべてこのメディアクエリ内に */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-group(*.card) {
    animation-duration: 0.35s;
    animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  }

  ::view-transition-old(*.card),
  ::view-transition-new(*.card) {
    object-fit: cover;
  }

  ::view-transition-old(root) {
    animation: fade-out 0.2s ease-in;
  }

  ::view-transition-new(root) {
    animation: fade-in 0.3s ease-out;
  }
}

/* 動きを減らす設定の場合は0秒で即座に切り替え */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation-duration: 0s !important;
  }
}

根本的に安全を取るなら、@view-transitionの宣言自体をprefers-reduced-motion: no-preferenceで囲み、トランジションを完全に無効化する方法もある。どちらを選ぶにせよ、アニメーションを無配慮に提供することだけは避けなければならない。

prefers-reduced-motion: no-preference(通常)
カードA → 0.35sのスケール&移動アニメーション
スムーズなモーフィングが再生される
prefers-reduced-motion: reduce(設定ユーザー)
カードA → 0sで即座に切り替え
視覚的な負荷を回避し、安全に遷移する
■ 設定に応じてアニメーションの有無を切り替えるのが基本

なお、prefers-reduced-motion: reduceのユーザー向けに、完全に0秒にする代わりに短いクロスフェード(0.15秒)を提供する手法もある。動きそのものをゼロにするのが最も安全だが、穏やかなフェードなら許容できるユーザーもいる。ただし、実際にその設定に依存するユーザーでテストするまでは、0秒を選択しておく方が無難だ。

プログレッシブエンハンスメントとブラウザ対応

プログレッシブエンハンスメントとブラウザ対応

ビュートランジションは、プログレッシブエンハンスメントの理想的な例だ。ブラウザが@view-transitionルールを理解しなければ、単に無視され、通常のページ遷移が行われる。何も壊れない。エラーもレイアウトシフトも発生しない。Firefoxがまだサポートしていなくても問題はなく、Safari 18.2以降やChrome、Edgeではフル機能が使える。

唯一、@supports (view-transition-name: none)でガードする価値があるのは、トランジション専用のスタイル(スナップショット品質向上のためのcontain: paintなど)を適用する場合だけだ。それ以外は、古いブラウザでも何もせずにそのまま動く。

この記事のポイント

  • view-transition-nameは一意の識別子、view-transition-classはスタイルをグループ化するフック。クラスを使えば、数百要素でも数行のCSSでアニメーションを統制できる。
  • nameはページロード時に全要素に付与せず、pageswapとpagerevealを使ってクリック時に動的に設定する。これでパフォーマンスが大幅に向上する。
  • トランジション完了後は必ずnameをクリアし、古い名前の衝突を防ぐ。
  • prefers-reduced-motionの対応は必須。すべてのアニメーションカスタマイズをメディアクエリ内に閉じ込め、設定ユーザーには0秒または短いフェードを提供する。
  • ビュートランジションはプログレッシブエンハンスメント。未対応ブラウザでは何も起こらず、通常のページ遷移となる。
海田 洋祐
Stack Overflow質問数が激減、AI時代に問いをやめた開発者の未来

Stack Overflow質問数が激減、AI時代に問いをやめた開発者の未来

2026年5月現在、Stack Overflowの月間質問数は3,000件を下回る水準にまで落ち込んでいる。2014年のピーク時には月間20万件を超えていたことを考えると、この10年余りで実に98%以上が消失した計算だ。

CSS-Tricksに掲載された分析記事は、この急落が単にAIの台頭だけでは説明できないと指摘する。コミュニティのモデレーション方針や初心者への閉鎖性が、ChatGPT登場以前からすでに質問数の減少を招いていたという。本記事では同記事の考察を軸に、AI時代における開発者の「問う力」の行方を掘り下げる。

重要な問いはこうだ。開発者が質問をやめた世界で、AIの学習データはどう更新されるのか。次世代のコード職人は育つのか。これらの懸念はCSS-Tricksの記事全体を貫く核心でもある。

Stack Overflow質問数の急落が示すもの

Stack Overflow質問数の急落が示すもの

Stack Overflowは2008年の設立以来、開発者にとって最大級のQ&Aプラットフォームとして機能してきた。しかしData Stack Exchangeで公開されている統計は、驚くべき下落曲線を描いている。

2014年には月間20万件以上の新規質問が投稿されていた。ところが2026年には月間3,000件にも満たない状況だ。このグラフは、単なるプラットフォームの衰退を超えて、ソフトウェア開発における知識共有の在り方そのものが変質したことを物語る。

2014年のピーク時(Before)
200,000 件/月
新規質問が活発に投稿され、回答も即時についていた
初心者 熟練者 誰でも質問
2026年の現状(After)
3,000 件/月未満
98%以上の質問が消失、回答の蓄積も鈍化
AI回答 ナレッジ停滞

このグラフが示す事実は重い。Stack Overflowはソフトウェア開発の集合知として15年以上にわたり機能してきたが、その流入がほぼ止まったに等しい。CSS-Tricksの記事では、この減少を「大量のレンガが降ってくるような衝撃」と表現している。

減少の原因はAIだけではない

減少の原因はAIだけではない

ChatGPTが公開されたのは2022年11月だ。しかしStack Overflowの質問数減少は、それよりずっと前の2014年から始まっていた。CSS-Tricksの記事は、AIを「最後のとどめ」と位置づけつつ、真の要因は別にあると分析する。

厳格化するモデレーションと閉じたコミュニティ

2014年以降、Stack Overflowは質問の品質を保つためにクローズ・削除の基準を厳格化した。重複質問は容赦なく閉じられ、「すぐに回答できない質問」も排除される方針が取られた。同サイト自身が「社交的ではないが、驚くほどうまくスケールする」と述べていたほどだ。

この運用はGoogle検索経由で既存の回答に誘導するモデルとしては合理的だった。しかし初めて質問しようとする初心者にとっては、門前払いの壁にしか見えなかった。CSS-Tricksの記事は「学びたいという意欲に対して罰を与えられるようなものだ」と表現している。モデレーションの厳しさがコミュニティの新規参加を阻み、質問数の漸減を招いたのだ。

従来のStack Overflow質問フロー(Before)
質問投稿 重複チェックでクローズ ダウンボート
※ 初心者は萎縮し、質問そのものを諦めるケースが多かった
現在のAI活用フロー(After)
質問を入力 LLMが即座に回答 判断なし・即時
※ ただし回答の正確性・セキュリティリスクは未検証のまま

変化の流れははっきりしている。質問を歓迎しないコミュニティの空気がまず参加者を減らし、そこに24時間即答してくれるAIが登場したことで、残っていた質問需要も完全に吸収された形だ。

AIは問題解決の代替になるか

AIは問題解決の代替になるか

AIはコードを書ける。だが「問題を解決できる」かは別の問いだ。CSS-Tricksの記事は複数の研究を引用しながら、この点を丁寧に解きほぐしている。

AI生成コードの品質

DeepMindのAlphaCodeは競技プログラミングで人間レベルの成績を収めた。しかし実務のソフトウェア開発は競技とは異なる。コーネル大学の研究によれば、AI生成コードは「一般に単純で反復的であり、未使用の構造やハードコードされたデバッグ処理を含みやすい」という。一方で人間のコードは「構造的複雑性が高く、保守性の問題が集中する傾向がある」と報告されている。

セキュリティ面ではさらに深刻だ。VeraCodeが100のAIモデルを対象に脆弱性テストを実施したところ、AI生成コードの45%にセキュリティ上の欠陥が見つかった。CSS-Tricksの記事は「十分な検証なしにAIコードをコピー&ペーストするだけであれば、深刻なバグや脆弱性に必ず直面する」と警告する。

AI生成コードの特徴(Bad)
単純かつ反復的な構造
未使用の変数・関数が残る
ハードコードされたデバッグ処理
45%にセキュリティ脆弱性
出典: Cornell大調査 / VeraCode
人間のコードの特徴(Good)
構造的複雑性が高い
コンテキストを考慮した設計
テスト・エッジケースの考慮
保守性の問題は多いが、意図は明確
出典: Cornell大調査

MITの研究も、AIは「良いコードを書けるが、ソフトウェアエンジニアのように思考し判断することはできない」と結論づけている。GitHubが2024年8月に公開した調査では、開発者の97%以上が仕事またはプライベートでAIツールを利用しているという。AIは遍在しているが、それを使いこなす職人技は依然として人間の側にある。

生産性とモチベーションのトレードオフ

Harvard Business Reviewの研究によれば、生成AIは問題解決の生産性を高める一方で、作業者のモチベーションを低下させる副作用がある。CSS-Tricksの記事はこの点を「AIは問題解決を支援する道具としては有効だが、創造性と問題解決アプローチを代替することはできない」とまとめている。

職人はすべての道具を使いこなす。AIもその一つにすぎない。道具の有効性は、それを作った職人の技量と、それを使う工夫によって決まる。CSS-Tricksの記事が引用するCraig D. Lounsbroughの言葉が端的に示す通りだ。

AIを賢く使うための自問

AIを賢く使うための自問

CSS-Tricksの記事では、著者自身が開発作業でAIを使う際に実践している4つのチェック項目が紹介されている。このリストは、AIへの過剰依存を避けつつ生産性を高める実践知として参考になる。

STEP 1 小さく具体的な質問に分割しているか
システム全体をまとめて尋ねるのではなく、各ステップを個別に検証できる粒度にする
STEP 2 出力内容を評価し、理解しているか
生成されたコードを将来にわたって保守・修正できるか自問する
STEP 3 参照元・情報源を確認しているか
回答の根拠が架空の文献でないか、信頼できる最新手法かを確かめる
STEP 4 エッジケースまでテストしたか
ユーザーが実際にどう使うかを理解するのは人間の役割。AIには難しい領域

この4つの自問は、AIにすべてを任せるのではなく、開発者自身が主体的にコードの品質と安全性に責任を持つためのガイドラインだ。CSS-Tricksの記事は「AIにすべてを委ねるのは大きな間違いだ」と明言している。

問いをやめた先にあるもの

問いをやめた先にあるもの

記事の後半で提起される最も本質的な問いはこれだ。開発者が質問することをやめた世界で、AIの学習データはどう更新されるのか。

CSSを例に取れば、ここ数年でネスト、ビュートランジション、コンテナクエリといった仕様が急速に進化した。数年前のコードと現在のコードでは書き方が根本的に異なる。もし新たな質問と回答の蓄積が止まれば、LLMは古いプラクティスに基づいたコードを出力し続けることになる。CSS-Tricksの記事は「私たちが質問をやめ、回答をやめれば、LLMは時代遅れになるのではないか」という懸念を示している。

質問が生まれ続ける世界(Before)
開発者の質問 回答の蓄積 ナレッジ更新 AIの学習データ
※ 技術の進化に合わせて新しい質問と回答が継続的に生まれる健全なループ
質問が止まった世界(After)
質問の消失 回答の枯渇 ナレッジの停滞 LLMの陳腐化
※ CSSネストやコンテナクエリなど新技術に対応できないLLMが増えるリスク

Stack Overflowの共同創業者Jeff Atwoodはかつて「Stack Overflowはあなた自身だ」と述べた。同僚プログラマーを信頼することがプラットフォームの核心だった。CSS-Tricksの記事は読者に問いかける。「LLMも同じことをしてくれるだろうか」と。

人間はこれまでも新しい道具とのバランスを見つけてきた。AIも例外ではないだろう。しかし、問うことをやめたコミュニティからは、新しい知見も、次世代の職人も生まれにくい。その危惧がこの記事の底流にある。

この記事のポイント

  • Stack Overflowの月間質問数は2014年の20万件超から2026年には3,000件未満へと98%以上減少した
  • 減少の原因はAIだけではなく、2014年以降の厳格なモデレーションと初心者排除のコミュニティ構造が先行要因として存在する
  • AI生成コードの45%にセキュリティ脆弱性があり、コピー&ペーストだけでは深刻なリスクを招く
  • 開発者は小さな質問への分割、出力評価、参照元確認、テストの4ステップでAIと向き合うべきである
  • 質問と回答の蓄積が止まれば、LLMは新技術に対応できず陳腐化するという構造的リスクがある
海田 洋祐
84万超の検索分析が示すAI Overviewの行動変容

84万超の検索分析が示すAI Overviewの行動変容

GoogleがAI Overviewの表示を拡大するなか、検索結果上でのユーザー行動が大きく変わり始めている。Search Engine Journalが公開した最新の調査レポートでは、約84.6万件の米国ユーザーの検索セッションをもとに、クリック前の画面内行動を詳しく分析した。

同レポートの著者Eric Van Buskirk氏によれば、AI Overviewが表示されるとユーザーはSERP上に長く留まり、検索結果を何度も確認し、比較し、そしてクリックの判断を慎重に行うようになるという。この変化は、単にランキング上位を狙うだけであったこれまでのSEO戦略に再考を迫る。

今回は、同調査から明らかになった4つの核心的な発見と、それが自社サイトやブランドにとって何を意味するのかを、わかりやすく整理する。

1. AI Overviewは検索意図に関係なくSERP滞在時間を延ばす

1. AI Overviewは検索意図に関係なくSERP滞在時間を延ばす

調査データと分析手法の概要

今回の調査は、ClickStream SolutionsがSurfer SEOから提供された匿名化クリックストリームデータを解析したものだ。対象は2026年2〜3月の米国ユーザー約84.6万セッション。1秒間隔で取得されたカーソル位置情報を用いて、ユーザーが検索結果ページ上でどこを読み、どこで止まり、どの程度スクロールしたかを追跡した。

分析において特に重要なのが「残留率(滞留率)」だ。検索結果が表示されてから3秒後、6秒後…21秒後の各時点で、どれだけのユーザーがまだ同一のSERP上でアクティブな状態にあったかを、情報検索、ローカル、ナビゲーショナル(ブランド名検索)、トランザクショナル(購入意図)、動画の5つの検索タイプに分けて比較している。

AI Overviewが行動差を消し去る

AI Overviewが表示されていない場合、検索意図によってSERPからの離脱スピードは大きく異なっていた。最も早く離脱するナビゲーショナル検索では、21秒後にSERP上に残っているユーザーはわずか12%。反対に、地図や口コミ情報が豊富なローカル検索では、32%がまだアクティブだった。

ところがAI Overviewが表示された途端、この差がほとんどなくなる。同じ21秒後でみると、どの検索タイプでも42%〜49%のユーザーがSERP上に留まっており、全タイプがきわめて似た行動パターンを示すようになる。つまり、AI Overviewがある状況では、ユーザーはもともとの検索意図によらず、一様に時間をかけて情報を読み込むモードに切り替わっているのだ。

AI Overviewなし(Before)
情報検索 21.6%
ローカル 32.3%
ブランド名 12.0%
購入意図 24.9%
動画 23.4%
AI Overviewあり(After)
情報検索 45.4%
ローカル 41.9%
ブランド名 45.8%
購入意図 47.4%
動画 48.5%

※21秒経過時点でのSEPR残留率。AI Overviewの有無で行動差が縮小する。

2. ブランド名検索ユーザーが最も大きな影響を受ける

2. ブランド名検索ユーザーが最も大きな影響を受ける

勝手に来ると思われていたユーザーが変わる

最も顕著な変化が起きたのは、ナビゲーショナル検索、つまりブランド名やサイト名を直接入力して来るユーザー層だ。従来であれば、こうしたユーザーは迷いなく目的のサイトへクリックするため、SERPからの離脱は非常に早く、21秒後の残留率はわずか12%だった。

しかしAI Overviewが表示されたケースでは、同じブランド名検索でも21秒後に46%がまだSERP上に残っている。彼らは単にサイトのURLを見つけるだけでなく、AI Overviewの要約や周辺の情報を読んだり、検索結果を比較したりしながら、クリックするまでにより多くの時間をかけている。

カーソル移動範囲の拡大が示す「探る」行動

カーソル移動の分析でも同様の傾向が確認された。AI Overviewがない場合、ブランド名検索ユーザーのカーソルは非常に狭い範囲に集中し、画面全体に対する移動範囲はわずか8%だった。これは、目的のリンクだけを素早く探す行動パターンを示している。

一方、AI Overviewがあるとカーソルは画面の27.5%にまで広がる。彼らは結果のスニペットをあちこち読み返し、AI Overview内のテキストも追いながら、より広い視点で判断していることがわかる。ブランドにとっては、これまでほぼ確実に得られていた直接流入が、検索結果の質と情報の明快さによって左右されるフェーズに移行しつつあると言える。

3. ユーザーは素早くクリックせず、比較しながら熟読する

3. ユーザーは素早くクリックせず、比較しながら熟読する

静止時間と画面カバー率の相反する増加

AI Overviewが表示されると、一見矛盾する2つのカーソル行動が現れる。ひとつはカーソルが静止している時間の増加で、セッション全体の44%が静止状態になる(AI Overviewなしでは29%)。もうひとつは、カーソルがカバーする画面範囲の拡大で、ビューポートの83%にまで及ぶ(同66%)。

この組み合わせは、ユーザーが「走り読み」から「立ち止まって読む」モードに切り替わったことを示唆している。断片的に情報を拾うのではなく、ある箇所でじっくりテキストを読んだあと、別のエリアにカーソルを移動してまた読む、という行動が繰り返されているのだ。

逆スクロールの多発が証明する比較検討

さらに決定的なのがスクロールの逆走だ。調査では、ユーザーがSERPを下にスクロールしたあと、再び上に戻る「逆スクロール」の発生率と、全スクロール量に占める逆方向スクロールの割合を計測した。AI Overviewがない場合、逆スクロールを経験するユーザーは51%で、その際の戻り量は全スクロールの27%だった。

ところがAI Overviewがあると、逆スクロール発生率は59%に上昇し、さらに逆方向スクロールが全スクロールの47.5%を占めるまでになる。つまり画面を上下に行ったり来たりしながら、複数の検索結果やAI Overviewの情報を照合しているのだ。この行動は、単なる上から下への「眺め」ではなく、能動的な比較検討が行われている証拠と言える。

AI Overviewなし
↓ 下へスクロール (全体の73%)
↑ 逆スクロール (全体の27%)
逆スクロールを行うユーザー: 51%
AI Overviewあり
↓ 下へスクロール (約52.5%)
↑ 逆スクロール (約47.5%)
逆スクロールを行うユーザー: 59%

※逆スクロールの比率がほぼ半々になり、上下に行き来する比較行動が増えたことがわかる。

4. 検索結果スニペットに求められる「精査に耐える情報」

4. 検索結果スニペットに求められる「精査に耐える情報」

タイトルとメタディスクリプションの重みが増す

これまでの検索行動のモデルは「上位の結果をざっと見て、一番適当なものをクリックする」だった。しかしAI Overviewが登場したいま、ユーザーは複数の結果をじっくり読み比べ、ときにはスクロールを戻して再確認しながら、最も信頼できる情報を選ぼうとする。

この変化が意味するのは、単に上位表示されているだけでは不十分で、検索結果のスニペット(タイトルとメタディスクリプション)が極めて重要になるということだ。曖昧で具体性のないスニペットは、一瞬のスキャンならクリックを誘えても、比較検討の場面では競合の明確な説明に負けてしまう。

ブランドが今すぐ見直すべきポイント

調査レポートから導かれる実務上の示唆は明快だ。まず、自社の検索結果の表示内容を「パッと見の印象」だけでなく、「じっくり読んだときに納得感があるか」という視点で見直す必要がある。

具体的には、タイトルタグに検索意図を明確に反映させ、メタディスクリプションにはページの独自価値を端的に盛り込む。AI Overviewが表示されるクエリでは、ユーザーは15〜20秒かけて熟考してからクリックするケースも増えている。その時間を味方につけるために、スニペットを「選ばれる理由」を語る場として設計することが重要だ。

5. この記事のポイント

  • AI Overviewが表示されると、ユーザーは検索意図にかかわらずSERPに長く留まり、結果を比較検討する行動が顕著になる
  • ブランド名を直接入力するユーザーでも、AI OverviewがあるとSERPでの滞留時間が4倍近くに伸び、クリックの確実性が低下する
  • カーソルの静止時間増加と画面カバー率の拡大、逆スクロールの多発は、ユーザーが「走り読み」から「熟読比較」へ移行した証拠
  • 検索結果スニペット(タイトルとメタディスクリプション)の情報の明快さが、クリック獲得の成否を分ける最重要ファクターになる
海田 洋祐
CloudflareがClaude Managed Agentsと統合、エージェントの実行基盤を刷新

CloudflareがClaude Managed Agentsと統合、エージェントの実行基盤を刷新

CloudflareがAnthropicと連携し、Claude Managed AgentsをCloudflareのサンドボックス環境と統合した。この新たな統合により、エージェントのコード実行からブラウザ操作、プライベートサービスへの接続までを、Cloudflareのプラットフォーム上でより柔軟に制御できる。

従来、Claude Managed AgentsはAnthropic側のインフラに完全に依存していた。今回の発表で「頭脳」であるClaudeの推論ループと「手足」であるコード実行基盤が分離され、後者をCloudflare上で運用できるようになった。

開発者は数分でテンプレートをデプロイし、セキュリティ強化やミリ秒単位のサンドボックス起動、内部サービスへの安全な接続といったメリットを得られる。この記事では、統合の仕組みと実務への影響を具体的に掘り下げる。

Claude Managed AgentsとCloudflareが目指すもの

Claude Managed AgentsとCloudflareが目指すもの
従来の構成
Claude推論ループもコード実行も、すべてAnthropic側のインフラで処理されていた。
課題:インフラ選択の自由度が低く、自社サービスとの統合が難しい
今回の統合後
Claudeの推論ループはAnthropic側。コード実行基盤(サンドボックス)はCloudflareで動かせる。
効果:セキュリティ、スケール、観測性をすべてCloudflareでコントロール

この構成で得られるのは単なる「場所の変更」ではない。インフラをCloudflareに移すことで、エージェントの振る舞いを細かく監視し、内部サービスとの通信を暗号化し、必要なリソースだけを動的に割り当てられるようになる。

Cloudflare Blogの記事では、この仕組みを「頭脳から手足を切り離す」と表現している。開発者はClaudeの高い推論能力をそのまま活かしつつ、実行環境だけを自社ポリシーに合わせてカスタマイズできるわけだ。

Cloudflare環境の仕組み

Cloudflare環境の仕組み

統合をデプロイすると、Cloudflare上にWorkersベースのコントロールプレーンが立ち上がる。Claude Agentがセッションを開始するたび、このコントロールプレーンがサンドボックス環境を割り当て、コード実行やCLIツールの操作、ブラウザ操作などを代行する。

STEP 1
Claude Agentがタスクを開始し、コントロールプレーンへリクエストを送信
STEP 2
Workersがセッションごとに隔離されたサンドボックスを起動
STEP 3
コード実行やファイル操作を実施。セッション間で状態を保持
STEP 4
ダッシュボードやSSHで稼働状況をリアルタイムに確認可能

サンドボックスはセッションがスリープしても状態を自動的に保持する。コンテナイメージのカスタマイズやインスタンスサイズの調整もオプションで指定でき、既存の監視ツール(DatadogやSplunk)へのログ連携にも対応している。

特筆すべきは、Cloudflareのダッシュボードからエージェントの状態を可視化し、必要に応じてSSHでサンドボックス内部に入れる点だ。大規模なエージェント運用では、トラブルシューティングのしやすさが運用コストを大きく左右する。この設計は現場の要求をよく踏まえている。

インターネット規模のエージェント実行基盤

インターネット規模のエージェント実行基盤

エージェントが本格的に普及すると、企業は1人のユーザーに対して複数のエージェントを同時に動かす必要が出てくる。従来のマイクロVM方式では、エージェントの数だけVMを起動し続けるため、リソースとコストが線形に増加してしまう。

Cloudflareはこの課題に対し、V8 Isolateを使った軽量サンドボックスを提供する。Dynamic WorkersとCodemodeを組み合わせることで、ミリ秒単位でサンドボックスを起動し、フルVMよりはるかに少ないリソースで任意のコードを実行できる。

マイクロVMサンドボックス
Linuxベースのフル機能。アプリケーション開発やCLIツールの実行向け
起動時間:秒単位。リソース消費は比較的多い
vs
V8 Isolateサンドボックス
軽量な隔離環境。ファイルシステムも持つが、VMより遥かに小さなフットプリント
起動時間:ミリ秒単位。数万の同時実行も可能

エージェントのセットアップ時にバックエンドタイプとして「isolate」を選択するだけで、この軽量モードに切り替えられる。数万規模の同時エージェントを扱うユースケースでは、コスト効率が数十倍変わる可能性がある。

もちろん、Linuxツールをフル活用する開発エージェントには、引き続きマイクロVMベースのCloudflare Containersを使える。用途に応じて2種類の実行環境を選択できる点が、この統合の実用的な強みだ。

エージェントワークロードのセキュリティ

エージェントワークロードのセキュリティ

エージェントが組織の内部データやサービスにアクセスするとき、最大のリスクは認証情報の漏洩だ。Cloudflareの統合では、アウトバウンドプロキシを使い、サンドボックスから外部へ出る通信に対して動的に認証情報を注入する仕組みを備えている。

この設計のポイントは、エージェント自身はクレデンシャルを知らないことだ。プロキシがゼロトラストベースでリクエストに署名やトークンを付与するため、万が一サンドボックスが侵害されても、認証情報そのものが盗まれるリスクを抑えられる。

エージェント 外部サービスへリクエスト送信 プロキシ 認証情報を注入 内部API 安全に応答
エージェントはクレデンシャルを保持しない  プロキシがゼロトラスト認証を代行する

また、Cloudflare MeshとWorkers VPCを使えば、インターネットに一切公開していない内部サービスにも、ポスト量子暗号で保護されたトンネル経由で接続できる。VPNや踏み台サーバーなしでプライベートサービスと通信できる点は、インフラ担当者にとって大きな利点だろう。

プロキシはテナント単位やエージェント単位でポリシーを適用できる。特定のエンドポイントだけを許可リスト化し、それ以外の通信を遮断するといった細かな制御も、コード数行で実装可能だ。

エージェントに必要なツール群

エージェントに必要なツール群

ブラウザ操作の完全な制御

エージェントがウェブと対話する際、単純なHTTPリクエストでは不十分な場面が多い。JavaScriptを多用するモダンなウェブアプリケーションの操作や、QA用のスクリーンショット取得、フォーム入力の自動化には、実際のブラウザが必要になる。

CloudflareのBrowser Runは、エージェントにプログラム可能なブラウザを与える仕組みだ。検索、実行、スクリーンショット、ページのMarkdown変換など、複数のツールがデフォルトで利用できる。

セッションの録画機能も備わっており、エージェントがブラウザ上で何をしたかを後から完全に監査できる。許可リストや拒否リストを使ったアクセス制御も可能で、野放図なウェブアクセスを防げる。

メール送受信とプライベート接続

エージェントにメールアドレスを割り当て、送受信を自律的に行わせる機能も統合済みだ。Cloudflare Email Serviceと連携し、任意のドメインでエージェントがメールを送信できる。顧客対応の自動化や、転送されたメールへの返信といったユースケースに適している。

内部サービスへの接続にはcall_serviceツールが用意されており、Cloudflare MeshやWorkers VPC経由でプライベートAPIを安全に呼び出せる。Workers AIを使った画像生成ツールも標準で組み込まれており、Claudeのテキスト推論と組み合わせたマルチモーダルなワークフローを構築できる。

カスタムツールの追加

リポジトリをフォークし、独自のツールを追加するのも容易だ。例えばCloudflare R2にファイルをアップロードし、公開URLを返すツールを数行のコードで定義できる。以下はCloudflare Blogで示されたコード例を簡略化したものだ。

defineTool({
  name: "r2_host_file",
  description: "サンドボックスからR2にアップロードし公開URLを取得",
  inputSchema: z.object({
    key: z.string(),
    content: z.string(),
    contentType: z.string()
  }),
  run: async ({ key, content, contentType }, { env }) => {
    await env.PUBLIC_BUCKET.put(key, content, { httpMetadata: { contentType }});
    return `${env.PUB_R2_URL}/${encodeURI(key)}`;
  }
})

Workers AIを使ったエッジ推論や、Dynamic Workersによる動的なアプリケーションホスティング、Artifactsを使ったGit管理の追加など、Cloudflare Developer Platform全体をエージェントの拡張に活用できる。インフラ管理を意識せず、関数を書いてデプロイするだけで機能追加が完了する設計だ。

この記事のポイント

  • Claude Managed Agentsの実行基盤をCloudflare上に構築できるようになった
  • 「頭脳(Claude)」と「手足(Cloudflareサンドボックス)」の分離で、インフラ選択の自由度が向上した
  • V8 Isolateを使った軽量サンドボックスで、ミリ秒起動と低コストの大規模実行が可能
  • アウトバウンドプロキシによるゼロトラスト認証で、エージェントのセキュリティを強化
  • ブラウザ操作、メール送受信、内部サービス接続などのツールが標準装備されている
海田 洋祐
Prisma Next早期アクセス開始、型安全DBコントラクトとエージェント連携

Prisma Next早期アクセス開始、型安全DBコントラクトとエージェント連携

Prisma Nextの早期アクセスが2026年5月22日に開始された。PostgresとMongoDBを対象に、データベース定義をコントラクトとして記述すれば、マイグレーションや型チェックをフレームワークが自動処理する。エージェントと連携する開発ワークフローにより、データ層の構築速度が大幅に向上する見込みだ。

開発者がコントラクトを書くと、あとはPrisma Nextがデータベースマイグレーション、クエリの型検査、エラー時の意味のあるメッセージを生成する。エージェントがコードを提案し、型検査を通過することで、安全なクエリが担保される仕組みだ。

1行のコマンドで始まるオンボーディング

1行のコマンドで始まるオンボーディング

新しいフレームワークを習得するには、ドキュメントを読み、小さなプロジェクトで試行錯誤を重ねる。慣れるまでに数週間を要することも多い。Prisma Nextはその学習曲線を1行のコマンドで解消する。npm create prisma@next を実行すれば、プロジェクトの骨組みと、エージェントを即座に専門家にする多数のスキルが自動生成される。

npm create prisma@next

ドキュメントを熟読する代わりに、エージェントがフレームワークの慣用句をリアルタイムに提示する。質問があればエージェントに尋ねればよく、コマンドの意味や設計の意図をその場で説明してくれる。まるで熟練者が隣で教えてくれているような体験だ。

従来のフレームワーク学習
STEP 1 ドキュメントを通読する
STEP 2 小さなサンプルを作成する
STEP 3 エラーを修正しつつ慣用句を覚える
Prisma Nextのオンボーディング
STEP 1 npm create prisma@next を実行
STEP 2 エージェントがプロジェクトとスキルを構築
STEP 3 質問があればエージェントに聞くだけ
従来は3週間かかっていた学習が、数分で開発を始められる状態になる。

既存プロジェクトへの導入

既存のプロジェクトに追加する場合もnpx prisma-next@latest initで簡単にセットアップできる。その後、エージェントに「読んでいる本を追跡する小さなアプリを構築して」と指示するだけで、スキーマ定義からクエリ作成までを自律的に進める。

コントラクトを書けばデータベース管理はフレームワーク任せ

コントラクトを書けばデータベース管理はフレームワーク任せ

Prisma Nextの中心にあるのが、アプリケーションとデータベースの間の契約であるコントラクトだ。開発者はモデルを定義するだけで、クエリの型検査や自動補完、そしてデータベースマイグレーションの計画と実行をフレームワークに委ねられる。

// contract.prisma
model Book {
  id       String   @id @default(uuid())
  title    String
  author   String
  addedAt  DateTime @default(now())
}
コントラクト(contract.prisma)
アプリケーション 依存関係 データベース 契約に従ってデータを保管
自動化されるタスク
クエリの型検査
自動補完
マイグレーション計画の生成
データベースとの整合性維持
開発者はコントラクトを編集するだけで、データベースとの一貫性が保たれる。

このコントラクトは可読性が高く、更新も容易だ。Prisma Nextではこれが唯一の真実の情報源となる。モデルを変更すると、フレームワークが自動的にマイグレーションを計画し、データベースが常にコントラクトを満たすように調整する。

エージェントによる機能追加の流れ

「著者テーブルを追加し、名前と経歴を持たせ、書籍と紐付けてほしい」といった自然言語での指示をエージェントに与えるだけで、コントラクトが更新される。エージェントは型検査を通過するまで内部でクエリの検証を繰り返し、最終的に安全なコードを出力する。

型安全クエリと高速な反復開発

型安全クエリと高速な反復開発

Prisma Nextのクエリはすべてコントラクトに対して型検査される。開発者(あるいはエージェント)がクエリを書くと、型エラーが即座にフィードバックされる。このループが高速なため、アプリケーションの出荷速度が格段に上がる。

const books = await db.orm.Book
  .where({ addedThisWeek: true })
  .all();

このクエリは、コントラクトで定義されたBookモデルに基づいて型が決定される。エージェントが生成したクエリも同じ型検査を通過するため、人間が書いたコードと同等の安全性が保証される。

クエリ作成の反復ループ
1 エージェントがクエリを書く
2 型検査による即時フィードバック
3 型検査を通過したクエリが確定
4 データベースが対応可能な安全なクエリ
エージェントはツール呼び出し内でこのループを自律的に繰り返す。

マイグレーションを記述する必要がなくなる

マイグレーションを記述する必要がなくなる

データベースのマイグレーションは、多くの開発者にとって最も苦痛を伴う作業の一つだ。構文を正しく記述し、エラーをデバッグし、本番環境で失敗した場合にはさらに時間を費やす。Prisma Nextでは、この負荷から完全に開放される。

マイグレーション作業の変化
従来の方法(Before)
SQLマイグレーションファイルを手動で記述
構文ミスやデプロイ時のトラブルシューティング
本番障害発生時に復旧作業
Prisma Nextの方法(After)
エージェントがコントラクトを編集
フレームワークがTypeScriptマイグレーションを自動生成
トランザクションで安全に適用(Postgres)
エージェントは意図を伝えるだけで、実際のマイグレーションコードは書かずに済む。

TypeScriptで書かれたマイグレーションファイル

生成されるマイグレーションファイルはTypeScriptで記述され、人間が確認しやすい形式だ。prisma-next migration plan を実行すると、ops.json とともにレビュー可能なマイグレーションが出力される。エージェントがSQLを生成するのではなく、フレームワークが決定論的に生成するため、信頼性が高い。

// migrations/app/20260515T0900_add_book_published_at/migration.ts
export default class M extends Migration {
  override describe() {
    return { from: "sha256:…prev", to: "sha256:…next" };
  }

  override get operations() {
    return [
      addColumn("public", "book", {
        name: "publishedAt",
        typeSql: "timestamptz",
        defaultSql: "",
        nullable: true,
      }),
    ];
  }
}

Postgresでは、マイグレーション全体が単一のトランザクション内で実行される。どこかで問題が発生してもロールバックされ、データベースは元の状態を保つ。MongoDBの場合は段階的に安全な手順で計画される。こうした保護機構によって、エージェントに安全に作業を委任できる。

並行ブランチでのマイグレーション競合を自動解決

並行ブランチでのマイグレーション競合を自動解決

複数ブランチで同時にマイグレーションを作成すると、マージ時に順序の衝突が起きることがある。Prisma NextはGitのコミットグラフのようにマイグレーション履歴を扱い、この問題を解消する。

ダイヤモンド型マイグレーショングラフの例
main
branch A のマイグレーション
branch B のマイグレーション
main(両方マージ後)
フレームワークはこの形状を理解し、正しい適用順序を自動的に判断する。prisma-next migration graph で可視化できる。

prisma-next-migration-review スキルをエージェントが活用することで、新しいマイグレーションがmainに到達した場合も、グラフを読み取り、ブランチをリベースし、migration planを再実行する。結果として、衝突なくクリーンにマージできる。複数のエージェントが並行して作業しても、特別な手順を覚える必要はない。

定期的なアップグレードとフィードバックの簡便さ

定期的なアップグレードとフィードバックの簡便さ

Prisma Nextは日々アップデートされており、アップグレードも簡単だ。エージェントに「prisma nextをアップグレードして」と指示するだけで、最新バージョンに更新してくれる。問題が見つかった場合も、エージェントに「これはバグだ」「この機能が欲しい」と伝えれば、適切な報告チャンネルを選び、構造化されたフィードバックを提出してくれる。

コミュニティでの成果発表も歓迎されている。Prismaの公式アカウントで紹介されたり、Prisma NextのREADMEにリンクが掲載される可能性もある。本格的にデプロイする場合、Prisma Postgresの無料枠を活用できる。なお、Prisma Nextはまだ本番環境向けではない。プロダクションには引き続きPrisma 7を推奨するが、一般提供時にはPrisma 8となる予定だ。

この記事のポイント

  • Prisma NextはPostgresとMongoDBに対応し、データベース定義をコントラクトとして扱う
  • 1行のコマンドでプロジェクトをセットアップし、エージェントが即座に開発を支援する
  • 型安全クエリにより、人間とエージェントのどちらが書いたコードも信頼できる
  • マイグレーションはフレームワークが自動生成し、トランザクションで安全に適用される
  • 並行ブランチでの競合もグラフベースの履歴管理で自動解決される
海田 洋祐
中国語フィッシング即サービスの進化、リアルタイムOTP傍受とデジタルウォレット悪用の実態

中国語フィッシング即サービスの進化、リアルタイムOTP傍受とデジタルウォレット悪用の実態

フィッシングはもはや、偽のメールを大量にばらまくだけの手口ではない。中国語圏のアンダーグラウンドでは、フィッシングをサービス化したPhaaS(Phishing-as-a-Service)が急速に成熟している。2026年5月にGoogle脅威インテリジェンスグループが公開した分析によれば、これらのサービスは静的なパスワード収集から脱却し、リアルタイムでのワンタイムパスコード(OTP)傍受やデジタルウォレットの悪用へと移行している。

特に警戒すべきは、RCSやiMessageといった暗号化通信を配信経路に選び、多要素認証(MFA)をリアルタイムで突破する手口だ。AIによるフィッシングページの自動生成や、日本市場を狙った高度なローカライズも確認されている。もはや攻撃者のゴールはログイン情報の窃取にとどまらず、被害者の金融口座を直接掌握することにある。

中国語圏PhaaSエコシステムの独自性

中国語圏PhaaSエコシステムの独自性

これまでPhaaSといえばロシア語圏の攻撃者が主流だった。だが中国語圏のエコシステムは、単なる地域的な派生版ではなく、独自の文化とビジネスモデルを持つ市場として確立されている。Google脅威インテリジェンスグループが分析した12の現行PhaaSサービスは、いずれも成熟しており、多くが地域の犯罪エコシステムと密接に結びついている。

ロシア語圏との違い

最も大きな違いは標的の選び方だ。ロシア語圏の主要PhaaSは大企業の顧客を狙う傾向があるのに対し、中国語圏のサービスは一般市民を日和見的に攻撃するケースが多い。また、運用の透明さも対照的だ。ロシア語圏の攻撃者が厳格な運用セキュリティを保つのに対し、中国語圏の運営者はTelegramで高級な生活ぶりを公開するなど、オープンに活動する傾向がある。

もうひとつの特徴は、模倣対象となる正規組織のほぼすべてが中国国外の企業である点だ。つまり、これらのフィッシングサービスは自国市場を標的にしていない。広告や勧誘は中国で人気のWeChatやQQよりTelegramで行われることが多く、これは中国語圏のサイバー犯罪エコシステム全体に共通する傾向だ。

エコシステムの構造

PhaaSを中核としつつも、これらのサービス運営者は多岐にわたる付随サービスを提供している。個人識別情報(PII)の販売、ドメイン登録や仮想プライベートサーバー(VPS)の提供、マネーロンダリング支援、盗聴デバイスの販売、スパムメッセージ送信代行などだ。一部の業者は盗難支払いカード情報の取引にも関与している。フィッシング単体ではなく、犯罪の全工程をパッケージ化した総合サービスへと発展しているのである。

進化した攻撃手法

進化した攻撃手法

中国語圏PhaaSの技術的進化を理解するには、従来のフィッシングと現在の手口を比較するのが早い。下の図は、その変化を視覚化したものだ。

従来のフィッシング(Before)
被害者 偽サイトに認証情報を入力 攻撃者 後日ログイン試行
✕ OTPで失敗、MFA突破できず
新しいPhaaS(After)
被害者 偽サイトに認証情報とOTPを入力
管理パネル 情報がリアルタイム表示 攻撃者 OTPを即時使用
✓ MFAを突破、アカウント乗っ取り成功

従来型では攻撃者が認証情報を入手しても、OTPに阻まれてアカウントへ侵入できなかった。しかし現在のPhishingは、被害者がコードを入力する瞬間をリアルタイムで傍受し、数秒のうちに悪用する。MFAはもはや万能の防御策ではない。

RCSとiMessageを悪用した配信

攻撃の起点は、信頼できる通信手段の悪用だ。これらのPhishingサービスは従来のSMSではなく、RCS(リッチコミュニケーションサービス)やAppleのiMessageを多用する。両プロトコルはエンドツーエンド暗号化を採用しており、サーバーサイドで悪意あるリンクを検査・フィルタリングすることが難しい。つまり、キャリア側のセキュリティフィルターを素通りする。

さらに、開封確認やタイピングインジケーター、高解像度画像の送信といった機能が、メッセージの信憑性を高める。被害者にとっては正規の連絡と見分けがつかず、ソーシャルエンジニアリングの成功率を大幅に引き上げる要因となっている。

リアルタイムOTP傍受

被害者がフィッシングリンクをクリックして認証情報を入力すると、そのデータは攻撃者の管理パネルに即時表示される。攻撃者はこれを見ながら、被害者のアカウントでOTPリクエストを自らトリガーする。被害者は届いたコードを偽サイトに入力し、攻撃者はそれをコードの有効期限が切れる前に傍受して利用する。この一連の流れは数十秒で完結する。

デジタルウォレットトークン化

最終的な目的は、盗んだ支払いカード情報をデジタルウォレットに登録し、トークン化することだ。攻撃者は入手した認証情報とOTPを使い、被害者のカードを自分の管理するデバイスのウォレットにプロビジョニングする。トークン化されたカードは、高額決済や非接触支払い、ATM引き出しに利用可能になる。もはやログイン情報の窃取ではなく、金融口座への直接的な不正アクセスを実現する手口である。

AIによる自動化

複数の中国語圏PhaaS事業者がAIを運用に取り入れている。たとえば、UNC5814として追跡されている「Darcula」プラットフォームは、静的なテンプレートを廃止し、AI駆動のページ生成とPuppeteerのようなブラウザ自動化ツールを採用した。標的サイトのURLを入力するだけで、そのHTMLやCSS、JavaScript、ビジュアル要素を複製し、動的に偽ページを生成する。ページごとに構成が異なるため、シグネチャベースの検出はほぼ無力化される。

ローカライズのサービス化とYY来魚の事例

ローカライズのサービス化とYY来魚の事例

これらのPhishingサービスは、単に多言語対応するだけではない。地域ごとの消費者文化に深く入り込んだ、高度なローカライズを実現している。その代表例が「YY来魚」だ。

YY来魚の標的と戦術

2024年8月に広告が確認されたYY来魚は、119カ国をサポートするが、最大の注力先は日本だ。2025年11月以降、400以上のフィッシングテンプレートを顧客に提供してきた。対象は銀行や証券にとどまらず、AmazonやApple、PayPay、メルカリ、任天堂、東日本旅客鉄道(JR)、佐川急便など、日本の消費者生活に密着したブランドが並ぶ。

特筆すべきは、単なる偽ログインページの提供ではない点だ。日本の消費者が慣れ親しんだ「ポイント」や「報酬交換」の仕組みを悪用し、「有効期限切れのポイントを現金や商品に交換」といった偽の案内で被害者を誘導する。さらに、光熱費補助をかたるなど、足元の経済状況に乗じたルアーも展開している。

インフラと運営

YY来魚のフィッシングサイトには、人間による認証操作を求めるアンチボット画面が実装されていた。手動クリックがないと先に進めない仕組みで、セキュリティベンダーによる自動分析を妨害する。管理パネルでは、フィッシングで収集したデータの検索、カードのBIN番号に基づくブロックリスト管理、国別の配信制限、Alibabaのドメイン登録サービスを使った新規ドメインの登録と管理が可能だ。さらにシステム管理者はオペレーターユーザーを作成し、権限を細かく割り当てることができる。

YY来魚は日本に焦点を当てた一例だが、中国語圏PhaaSの網は米州、欧州、豪州、中東にも広がっている。特定の地域文化に合わせたローカライズを自動化できるインフラが、低スキルの攻撃者にも高精度なキャンペーンを可能にしている。

防御側の対策と展望

防御側の対策と展望

ユーザー教育は依然として重要な防御線だが、それだけでは不十分だ。中国語圏PhaaSの拡散は、人を介さない技術的な制御の必要性を強く示している。

FIDO2/WebAuthnへの移行

最も効果的な対策のひとつが、FIDO2/WebAuthnインフラへの移行だ。公開鍵暗号方式に基づくこの認証は、OTPのように通信経路上で傍受されるリスクがない。セキュリティキーは、ユーザーがフィッシングサイトに支払い情報を直接入力する行為そのものを防ぐことはできないが、盗まれた認証情報の悪用難易度を大幅に引き上げる。攻撃者がログインできない時点で、カード情報のトークン化も成立しない。

発行体側の検証強化

金融機関やカード発行体には、デジタルウォレットへのプロビジョニング時にリスクベース検証とデバイスフィンガープリントを組み合わせる対策が求められる。見慣れないデバイスや異常な利用パターンを検知し、トークン化の前に追加検証を挟む仕組みだ。

防御側の目標は「フィッシングの検知」から「盗まれた認証情報を技術的に無力化すること」へと移行しつつある。中国語圏のPhaaS事業者は現在もツールの改良を続けており、グローバルな影響力をさらに拡大しようとしている。対策もそれに合わせて進化させねばならない。

この記事のポイント

  • 中国語圏Phishing-as-a-Serviceは、OTPのリアルタイム傍受とデジタルウォレット悪用によりMFAを突破する
  • RCSやiMessageのエンドツーエンド暗号化が、キャリア側のフィルタリングを無効化し配信成功率を高めている
  • AIによる動的ページ生成で、シグネチャベースの検出回避が容易になった
  • 日本市場を狙うYY来魚のように、地域経済や消費者文化に深く適応したローカライズが進んでいる
  • 対策にはFIDO2/WebAuthnの採用と、カード発行体によるプロビジョニング時のリスク検証が有効
海田 洋祐