A03 ソフトウェアサプライチェーンの不備

自分で書いていないコードが、アプリと同じ権限で動く。入口は部品そのものだけでなく、それを作って届ける仕組み、つまり開発者の端末、リポジトリ、CI、成果物の置き場にもある。

OWASP Top 10:2025 A03 Software Supply Chain Failures。2021年版の A06 脆弱で古くなったコンポーネントを、依存、ビルド、配布の全体へ広げた新しいカテゴリ。コミュニティの調査では回答のちょうど50%が1位に選んだ。対応するCWEは一覧で6つ[1]。2026年11月時点の記載で書いています。

要点

  • 検査のデータでの出現は最も少ないが、CVEの悪用と影響の点の平均は全カテゴリで最も高い。OWASP は、少ないのは試験の難しさのためと見ている[2]。
  • 何が入っているか分からなければ直せない。直接と推移的な依存の全部を SBOM で把握し、脆弱性の情報と突き合わせ続ける。
  • 型は3つに分けて見る。既知の脆弱性を持つ部品を使い続ける、悪意ある版が入る、ビルドと配布の仕組みを乗っ取られる。
  • OWASP は、1人でコードを書いて本番まで出せる経路を無くす職務の分離と、全員への一斉の更新を避ける段階的な展開を求める[1]。

成立の条件

部品が作られてから本番で動くまでの、どの段でも、確かめずに次へ渡せば成り立つ。

部品のレジストリから開発者の端末、リポジトリ、CI、成果物の置き場、本番へと流れる各段に、それぞれの入口がある レジストリ 部品の公開先 開発の端末 IDE と拡張 リポジトリ コードと定義 CI と CD 秘密を持つ 成果物 イメージ置き場 本番 アプリの権限 脆弱な版 悪意ある版 拡張の乗っ取り 鍵の盗難 保護の無い ブランチ 固定しない 外部の手順 差し替え 署名なし A03 の範囲 この流れのどの段も。部品の中身や更新の完全性を確かめる細部は A08
図1 サプライチェーンの段と、それぞれの入口
  • 把握していない 直接と推移的な依存、端末側とサーバー側の部品の版を追っていない。OS、Webサーバー、データベース、実行環境も含む[1]。
  • 直さない 修正を月次や四半期の作業にして、その間を無防備にする。更新した部品の互換を試さないので上げられない[1]。
  • 固めていない CI と CD が、それが作る本番より弱い。1人でコードを書いて本番まで出せる[1]。

A08 ソフトウェアまたはデータの完全性の不備との境目について、OWASP は A08 を A03 より低い水準で完全性の検証と信頼の境界を扱うものと位置づける[2]。署名や外部のスクリプトの完全性の確かめは A08 で扱う。

型1 既知の脆弱性を持つ部品を使い続ける

脆弱性は、直接選んだ部品より、その下の推移的な依存に潜むことが多い。直接の依存だけを見ていると気づけない。OWASP は例に、Apache Struts 2 の CVE-2017-5638 と、Apache Log4j の CVE-2021-44228 を挙げる[1][9]。

アプリが直接選んだのはWebの枠組みと帳票の部品だけだが、その下で使われるログの部品に脆弱性があり、入力がそこまで届く アプリ package.json Webの枠組み 直接の依存 帳票の部品 直接の依存 ログの部品 推移的な依存。脆弱 直接の一覧には現れない 利用者の入力がログに渡る
図2 推移的な依存に潜む既知の脆弱性

悪い例。CI で範囲の中の最新を入れる

npm install   # 範囲の中で新しい版が入り、ロックファイルを書き換える

直した例。ロックファイルどおりに入れ、脆弱性で止める

npm ci                         # package.json とロックファイルが食い違えば失敗する
npm audit --audit-level=high   # 高以上の既知の脆弱性があれば失敗する
  • npm ci はロックファイルが要り、食い違えばロックファイルを直さずに失敗する[7]。版を意図して選び、要るときにだけ上げる、という OWASP の求めに合う[1]。
  • 版を固定すると、修正の版も自動では入らない。固定と、修正を早く入れる仕組みは対で置く。脆弱性の情報源は CVE、NVD、OSV を見張る[1]。
  • 保守が止まった部品と、更新できない部品は、それぞれ CWE-1104 と CWE-1329。修正が出ないなら別の部品へ移し、移せないなら仮想パッチで見張り、検知し、守る[1]。

型2 悪意ある版が入る

信頼していた部品の作者のアカウントや公開の仕組みが乗っ取られ、悪意ある版が正規の名前で出る。2025年9月の Shai-Hulud では、npm の500を超える包みが侵害された。入れた環境から GitHub の個人アクセストークンと、AWS、GCP、Azure の鍵を集めて公開のリポジトリへ上げ、見つけた npm の資格情報で他の包みにも悪意ある版を公開して広がった[3]。

悪意ある版をインストールすると導入時のスクリプトが走り、端末の資格情報を集めて外へ送り、npmの資格情報で別の包みにも悪意ある版を公開する 悪意ある版 正規の名前で公開 開発の端末か CI インストールで 導入時のスクリプトが走る 資格情報を集める npm とリポジトリの トークン、クラウドの鍵 外へ送る 公開のリポジトリなど 得た npm の資格情報で、別の包みにも悪意ある版を公開する 止める点 導入時のスクリプトを切る。トークンを最小で短命に
図3 自分で広がる悪意ある版の道筋。CISA の公表をもとにした

直した例。CI では導入時のスクリプトを走らせない

# .npmrc
ignore-scripts=true

# CI
npm ci --ignore-scripts
npm rebuild some-native-module   # 本当に要る部品だけ、中身を確かめてから個別に
  • ignore-scripts を有効にすると、依存の導入の前後に走るスクリプトが止まる。npm test のように明示して呼ぶスクリプトは走るが、その前後のスクリプトは走らない[8]。
  • CISA の勧めは、ロックファイルで影響を受けた部品を洗い出す、侵害の前の版に固定する、開発者の資格情報を全部回す、GitHub と npm にフィッシングに強い多要素認証を義務づける、ブランチの保護と秘密の走査を有効にする、こと[3]。
  • 公開の権限を持つトークンは、包みの単位と期限で絞る。開発の端末には公開の権限を置かない。
  • 新しい版を出た直後に全環境へ入れない。OWASP は、信頼していた作者が侵害された場合に備え、段階的な展開やカナリアで影響を限るよう求める[1]。

型3 ビルドと配布の仕組みを乗っ取られる

CI は本番へ出す鍵と、成果物を書き換える権限を持つ。CI の定義が外部の手順を可変の名前で呼び、権限を広く与えていると、外部の手順が書き換えられた時点で本番の鍵が外へ出る。

CIの定義が外部の手順を版の名前で呼ぶと、名前の指す中身が差し替えられたときに、CIが持つ本番の鍵と書き込みの権限を使われる 外部の手順 deploy-action@v2 名前の指す先は動く 差し替えられた中身 同じ v2 の名前 CI の実行 本番へ出す鍵 リポジトリへの書き込み 成果物の置き場への書き込み 全部を手順が使える 鍵が外へ クラウドを操作 成果物の改変 利用者へ配られる
図4 CI の外部の手順から本番の鍵へ届く道筋

悪い例。架空の CI の定義

permissions: write-all
jobs:
  deploy:
    steps:
      - uses: example-org/deploy-action@v2
        with:
          token: ${{ secrets.PROD_DEPLOY_KEY }}

直した例。中身で固定し、権限を絞り、本番の秘密を環境に閉じる

permissions:
  contents: read
jobs:
  deploy:
    environment: production   # 承認の要る環境にだけ本番の秘密を置く
    steps:
      - uses: example-org/deploy-action@3f1c0e5a9b7d2c4e6f8a0b1c2d3e4f5a6b7c8d9e  # v2.4.1
        with:
          token: ${{ secrets.PROD_DEPLOY_KEY }}
  • GitHub は、外部のアクションを完全な長さのコミットのハッシュで固定するよう勧め、タグでの固定は作者を信頼できる場合に限るとする。ハッシュの指す中身を差し替えるには SHA-1 の衝突を作る必要がある[6]。
  • OWASP は CI と CD に、職務の分離、アクセス制御、署名したビルド、環境に絞った秘密、改ざんの分かる記録を求め、成果物は環境ごとに作り直さず同じものを昇格させるよう求める[1]。
  • どこで、何から、どう作ったかの来歴を成果物に付ける。SLSA は来歴の有無を Build L1、ホストされたビルドの仕組みを L2、固めたビルドを L3 と段に分ける[5]。
  • CI の定義、IaC、ログの仕組み、成果物とコンテナの置き場の変更も、コードと同じく追跡と承認の対象にする[1]。

守り方

根本の直し方
  • ソフトウェア全体の SBOM を中央で作って管理し、推移的な依存まで追う[1][4]。
  • 使わない依存、機能、ファイルを外し、攻撃の面を減らす[1]。
  • 部品は公式の入手先から、安全な経路で、なるべく署名つきで取る。版は意図して選んで固定する[1]。
  • リポジトリ、開発の端末、CI と CD、成果物、IaC を固める。多要素認証と最小の権限、ブランチの保護、秘密をリポジトリに入れない[1]。
  • 1人でコードを書いて本番まで出せないようにし、別の人の確認を必ず挟む[1]。
  • アプリの寿命の間、更新を見張り、選び、当てる計画を持ち続ける[1]。
緩和の策
  • 部品の版を継続して棚卸しし、脆弱性の通知を購読する。OWASP Dependency-Track や Dependency-Check のような道具で自動にする[1]。
  • 修正できない部品には仮想パッチを当てて見張る。
  • 更新は段階的に広げる。
  • CI と本番の外への通信を絞り、集めた資格情報を外へ出しにくくする。

診断で見る所

A03 は外からの診断より、組織の中の点検とコードのレビューで見つかる。依存の扱いはチートシートが詳しい[10]。

観点見る所当たりの兆候
把握SBOM があるか。本番で動く成果物と一致するか無い。直接の依存しか載っていない
版ロックファイル、CI の導入の命令、イメージのタグロックファイルが無い。CI が範囲で入れる。latest のタグ
脆弱性既知の脆弱性の走査の結果と、直すまでの日数高と重大が長く残る。保守の止まった部品がある
導入時のスクリプトCI と開発の端末の npm の設定スクリプトが既定で走る
CI外部の手順の参照、ジョブの権限、秘密の置き場可変のタグで参照。write-all。本番の秘密が全ジョブから見える
リポジトリブランチの保護、レビューの必須、履歴の中の秘密1人で本番のブランチへ入れられる。履歴に鍵が残る
入手先レジストリの設定、取り込んだ部品の入手元非公式の配布元、署名を確かめない

関連するCWE

A03 の一覧に載る6つ[1]。

CWE名前この頁の型
CWE-1395Dependency on Vulnerable Third-Party Component型1
CWE-1104Use of Unmaintained Third Party Components型1
CWE-1329Reliance on Component That is Not Updateable型1
CWE-1357Reliance on Insufficiently Trustworthy Component型2、型3
CWE-10352017 Top 10 A9: Using Components with Known Vulnerabilities型1。前の版との対応のための分類
CWE-477Use of Obsolete Function型1
一覧の番号の食い違い

2026年11月時点の OWASP の一覧は、Use of Obsolete Function を CWE-447 と書くが、本文は CWE-477 と書く。MITRE では CWE-477 が Use of Obsolete Function で、CWE-447 は Unimplemented or Unsupported Feature in UI だ[11]。ここでは名前に合う CWE-477 を載せた。

参照

  1. A03:2025 Software Supply Chain Failures OWASP Top 10:2025
  2. Introduction, OWASP Top 10:2025 OWASP Foundation
  3. Widespread Supply Chain Compromise Impacting npm Ecosystem CISA。2025年9月23日
  4. Dependency Graph and SBOM Cheat Sheet OWASP Cheat Sheet Series
  5. SLSA v1.0 Security levels SLSA。OpenSSF
  6. Secure use reference GitHub Docs
  7. npm ci npm Docs
  8. npm config, ignore-scripts npm Docs
  9. CVE-2021-44228 NIST National Vulnerability Database
  10. Vulnerable Dependency Management Cheat Sheet OWASP Cheat Sheet Series
  11. CWE-477 Use of Obsolete Function MITRE