オープンセサミ:Open VSXの新スキャナーにおけるフェイルオープンのバグが、マルウェアをそのまま通過させた経緯

要約: Open VSXの新しい公開前スキャンパイプラインにフェイルオープンのバグが存在しました。公開エンドポイントに大量リクエストを送りつければ、スキャナーはスキップされ、悪意ある拡張機能が「合格」マーク付きで公開されてしまいます。報告から3日以内に修正済み。

  •  •  •

Open VSXは、Cursor、Windsurf、およびVS Codeフォークエコシステム全体を支える拡張機能マーケットプレイスです。このプラットフォームは最近、公開前スキャンパイプラインを導入しました。これは重要な取り組みであり、正しい方向性といえます。マルウェア検出、シークレットスキャン、バイナリ解析、名前のなりすまし防止——まさにエコシステムが切実に必要としていたインフラです。

しかし問題がありました。このパイプラインには、「スキャナーが設定されていない」と「すべてのスキャナーの実行に失敗した」の両方を意味する単一のboolean戻り値が存在していました。呼び出し元はその違いを判断できませんでした。そのため、負荷によってスキャナーが失敗した場合、Open VSXはそれを「スキャン対象なし」として扱い、拡張機能をそのまま通過させてしまっていました。

無料の公開者アカウントを持つ悪意ある攻撃者であれば誰でもこれを悪用できました。特別な権限も、内部アクセスも不要です。ただエンドポイントに大量リクエストを送って待つだけです。

私たちはこの問題を2月8日(日曜日)にOpen VSXチームへ報告しました。チームは問題を認識し、2月11日に修正をリリースしました。迅速かつプロフェッショナルな対応で、まさに理想的な脆弱性開示の進め方です。チームの皆さんに敬意を表します。

この脆弱性を「オープンセサミ」と呼ぶことにしました。では、一連の経緯を詳しく見ていきましょう。

スキャンパイプラインの仕組み

悪意ある拡張機能の脅威の増大に対応するため、Open VSXチームは公開前スキャンパイプラインの実装を開始しました(Issue #1331PR #1529)。その構想は、公開前にすべての拡張機能を検査する拡張可能な検証システムです。マルウェア検出、なりすまし防止、シークレットスキャン。検査に失敗した拡張機能は管理者レビューのために隔離されます。

パイプラインの動作は以下の通りです:

Image

  1. 公開者がAPIを通じて拡張機能をアップロードします。
  2. 拡張機能は保存されますが、スキャン完了まで非アクティブ状態となり、ダウンロードできません。
  3. スキャンは2つのフェーズで実行されます。まず、高速な同期チェックがインラインで実行され、いずれかのチェックが失敗すると拡張機能は即座に拒否されます。次に、登録されたすべてのスキャナーが並列バックグラウンドジョブとして送信されます。
  4. 完了サービスがこれらのジョブを監視し、すべて合格すると拡張機能がダウンロード可能になります。いずれかのスキャナーが脅威を検出した場合、拡張機能は管理者レビューのために隔離されます。
  5. 別の回復ウォッチドッグが定期的に停滞または失敗したスキャンをチェックし、再キューに入れます。

設定されたすべてのスキャナーを通過しない限り、いかなる拡張機能もユーザーに届かない——それが保証されているはずでした。では、どこで破綻するかを見ていきましょう。

バグは、ExtensionScanService.javaが結果を報告する方法と、その呼び出し元がそれをどう解釈するかに潜んでいます。

スキャン送信メソッドは以下の通りです:

Image

そして、PublishExtensionVersionHandler.javaの呼び出し元はこちらです:

Image

問題が見えますか?このbooleanは、まったく異なる2つの状況を混同しています:

(A)スキャナーが設定されていない。管理者による意図的な選択。有効化しても安全。

(B)すべてのスキャナージョブのキュー投入が失敗した。負荷による一時的なエラー。有効化は安全ではない

submitScannerJobsがfalseを返すとき、呼び出し元は毎回(A)と判断します。拡張機能は合格マークが付けられ、有効化され、ダウンロード可能になります。しかし負荷がかかった状況では、同じfalseが実際には(B)を意味します。スキャナーは存在しているのに、データベース接続プールが枯渇しているためキューに入れられなかったのです。

さらに悪いことに、同じパターンがExtensionScanJobRecoveryService.java——失敗したスキャンをキャッチして再試行するために設計された回復パス——にも存在していました。セーフティネット自体が、バックアップすべきシステムと同じ穴を持っていたのです。

攻撃の手口

特別な前提条件は不要で、攻撃者に必要なのはユーザーアカウントだけです。悪意ある拡張機能を複数用意し、それぞれを任意のペイロードを含む標準的な.vsixファイルとしてパッケージ化し、公開エンドポイントに大量リクエストを送りつけます。

なぜこれが機能するのか:各公開はスキャンパイプラインを起動し、ScanJobレコードの保存とJobRunrへのキュー投入が必要になります。両操作が共有プールのデータベース接続を奪い合います。十分な並行負荷がかかると、jobScheduler.enqueue()が例外を投げ始めます。catchブロックはエラーをログに記録して処理を続行します。すべてのスキャナーがキュー投入に失敗します。enqueuedCountはゼロのままです。メソッドはfalseを返します。

ゲートが開きます。拡張機能がopen-vsx.orgで公開されます。スキャン状態:合格。

私たちは制御された環境でのテストでこの動作を確認し、フェイルオープンのパスを確実に引き起こすことができました。本番環境での単一試行における競合ウィンドウはタイトですが、攻撃者は公開エンドポイントにレート制限がないため、ゼロコストで無制限にリトライできます。成功するのは時間の問題です。

侵入した拡張機能は、マーケットプレイス上の他の拡張機能と見分けがつきません。UIには、その拡張機能がすべてのセキュリティチェックをスキップしたことを示す表示は何もありません。正規に合格したものとまったく同じに見えます。

修正内容

いつものように、OpenVSXチームはこの脆弱性を素早く解消し、即座に対応して3日以内に修正しました。

この修正は根本的な曖昧さに対処しています。曖昧なbooleanはなくなりました。失敗は失敗として扱われます。

Image

Image

推奨される対応

直近のリスクは解消されています。Open VSXは2月11日に修正をリリースしました。脆弱性が存在していた期間中に新規または更新された拡張機能をインストールした場合は、それらを見直すことを検討してください。

この特定のバグを超えて、このパターンがより広い文脈でどういった意味を持つかを考える価値があります。公開前スキャンは重要な防御層ですが、それはあくまで一層に過ぎません。パイプラインの設計は適切でしたが、「何もすることがない」と「何か問題が発生した」を区別できない単一のbooleanが、インフラ全体を圧力下で開くゲートに変えてしまいました。これはよくあるアンチパターンです——フェイルオープンのエラーハンドリングが、正当な「何もすることがない」ケースのためのコードパスに隠れてしまうというものです。

同様のパイプラインを構築する場合は、失敗状態を明示的に表現してください。「作業不要」と「作業失敗」が同じ戻り値を共有しないようにしましょう。

これはまさに、Koiが検出するために構築されているギャップの種類です。私たちのリスクエンジンは拡張機能の動作——ネットワークリクエスト、ファイルシステムアクセス、コードパターン——を詳細に分析し、マーケットプレイスのスキャナーが実行されたかどうかに関わらず悪意ある意図を検出します。デモを予約して、その仕組みをご確認ください。

開示タイムライン

  • 2026-02-08(日曜日):Open VSXチームへ脆弱性を直接報告
  • 2026-02-11(火曜日):Open VSXチームが報告を認識
  • 2026-02-11(火曜日):コミット 64720ccで修正をリリース

関連CWE

  • CWE-636(セキュアでない失敗処理):核心的な問題——スキャナーの失敗が拡張機能のブロックではなく承認につながった。
  • CWE-755(例外条件の不適切な処理):enqueue()の例外がキャッチされてログに記録されたが、処理結果に影響しなかった。
  • CWE-362(競合状態):この攻撃は、スキャン中に接続プールを枯渇させるために並行公開のタイミングに依存している。
  • CWE-400(制御されないリソース消費):公開エンドポイントにレート制限がなく、接続プールの無制限な枯渇を許してしまった。

翻訳元: https://www.koi.ai/blog/open-sesame-how-a-fail-open-bug-in-open-vsxs-new-scanner-let-malware-walk-right-in

ソース: koi.ai