生成AIによるプログラミングは、ついに「コードを書く」段階から、そのコードに潜む未知の脆弱性を探し、異常を再現し、修正パッチまで作る段階へ入り始めました。

その象徴となる技術が、OpenSSFで開発されているOSS-CRSです。

OSS-CRSは、ソースコードへ単純な静的解析を実行して既知の危険パターンを探すだけのツールではありません。

LLM、ファジング、静的解析、動的解析、サニタイザー、クラッシュ再現、パッチ生成といった複数の技術を組み合わせ、ソフトウェアの脆弱性を自律的に発見・検証・修正するCyber Reasoning Systemを動かすためのオープンな実行基盤です。

簡単に言えば、次のような工程をAIとセキュリティツールへ実行させることを目指しています。

  1. 対象ソフトウェアの構造を解析する
  2. 攻撃経路になり得る処理を探す
  3. ファジング用の入力やハーネスを生成・改善する
  4. 異常終了やメモリ破壊を発見する
  5. クラッシュを再現するPoVを保存する
  6. 原因となったコードを特定する
  7. 修正パッチを生成する
  8. 修正後にビルド、テスト、再現確認を行う

これまで、こうした作業には高度なセキュリティ研究者、ファジング専門家、プログラム解析の知識が必要でした。

OSS-CRSは、その全工程を完全に無人化する完成品ではありません。しかし、これまで別々に存在していた脆弱性発見・再現・トリアージ・修正技術を、共通の形式で組み合わせられる基盤として非常に重要です。

本記事では、OSS-CRSが生まれた背景から、Ubuntuへの導入、公式のlibxml2を使った基本検証、LLMを利用するAtlantis系CRSの実行、Claude Codeによるバグ発見・修正、さらにローカル専用の脆弱なサンプルプログラムを使った安全な検証まで詳しく解説します。

本記事の手順は、自分が所有・管理するソースコード、または検証を許可されたオープンソースプロジェクトだけで実行してください。第三者のシステム、Webサイト、サービスを無断で検査するための手順ではありません。


目次

DARPAのAI Cyber Challengeで何が起きたのか

OSS-CRSを理解するには、米国DARPAが実施したAI Cyber Challenge、通称AIxCCを知る必要があります。

AIxCCは、DARPAとARPA-Hが連携し、AIを利用して重要なオープンソースソフトウェアの脆弱性を自動発見・修正するシステムを競わせた大規模コンテストです。

Anthropic、Google、Microsoft、OpenAI、Linux Foundation、OpenSSF、DEF CON、Black Hatなども協力組織として参加しました。

決勝大会では、参加チームが開発したCyber Reasoning Systemが、合計約5,400万行の実在するソフトウェアを解析しました。

AIxCC公式発表によると、競技全体では次の成果が得られています。

  • 63件の合成脆弱性のうち54件を発見
  • 発見率は86%
  • 43件へ修正パッチを生成
  • 合成脆弱性に対する修正率は68%
  • 競技用に挿入されたものではない実在の未知脆弱性を18件発見
  • 実在の未知脆弱性に対して11件のパッチを提出

優勝したのが、Georgia Tech、Samsung Research、KAIST、POSTECHの研究者らで構成されたTeam Atlantaです。

Team Atlantaのシステムは、競技のスコア対象ラウンドで次の結果を残しました。

  • 脆弱性発見:43件
  • 成功したパッチ:31件
  • C言語の未知脆弱性:3件
  • Javaの未知脆弱性:3件
  • 優勝賞金:400万ドル

Team Atlantaが開発したシステムがATLANTISです。

ATLANTISは、LLMだけで脆弱性を探すものではありません。

LLMによるコード理解と、シンボリック実行、静的解析、指向性ファジング、カバレッジ分析、クラッシュ再現など、従来型のプログラム解析技術を組み合わせています。

重要なのは、「AIがセキュリティツールを置き換えた」のではなく、AIが複数の専門ツールを組み合わせ、解析の方向付けや判断を行うようになった点です。

AIxCC公式サイト:

DARPA Artificial Intelligence Cyber Challenge


なぜOSS-CRSが必要になったのか

AIxCC終了後、各チームのCyber Reasoning Systemはオープンソースとして公開されました。

しかし、大きな問題がありました。

競技用CRSの多くは、AIxCC専用のクラウド基盤、API、ストレージ、実行形式へ強く依存していました。

ソースコードが公開されても、そのまま一般企業やOSS開発者がローカルPCへ導入し、任意のプロジェクトに対して実行するのは困難だったのです。

OSS-CRSは、この問題を解決するために開発されました。

OSS-CRSが提供するのは、単一の脆弱性スキャナーではありません。

異なるチームが作ったCRSを、共通のインターフェースで準備・ビルド・実行し、成果物を交換できるオーケストレーションフレームワークです。

公式リポジトリ:

OpenSSF OSS-CRS

公式ドキュメント:

OSS-CRS公式サイト

OSS-CRSの主な特徴

  • CRSを共通形式で実行できる
  • OSS-Fuzz形式のプロジェクトを対象にできる
  • 複数のCRSを同じキャンペーンで組み合わせられる
  • CPUコアとメモリをCRSごとに制限できる
  • LLMの利用予算をCRSごとに制限できる
  • PoV、シード、バグ候補、パッチをCRS間で交換できる
  • ローカルDocker環境で実行できる
  • 独自の脆弱性発見・修正エージェントを追加できる

OSS-CRSは「Webサイト脆弱性診断ツール」ではない

ここは誤解しやすい部分です。

OSS-CRSへWebサイトのURLを渡し、「このサイトを攻撃してください」と実行するものではありません。

OSS-CRSの基本的な対象は、ソースコードとビルド環境を用意できるプロジェクトです。

特に、Google OSS-Fuzzと互換性のある形式が標準になっています。

したがって、WordPressサイトをURLだけ指定して検査する用途ではありません。

WordPressプラグイン、PHPライブラリ、独自パーサーなどを対象にする場合は、対象コードを実行するためのファズハーネスやOSS-Fuzz形式のビルド定義を作成する必要があります。


OSS-CRSの全体構成

OSS-CRSの処理は、大きく三段階に分かれます。

prepare
   ↓
build-target
   ↓
run

1.prepare

使用するCRSのリポジトリやDockerイメージを取得し、実行に必要な環境を準備します。

LLMを利用するCRSでは、LiteLLMなどのLLM接続基盤も準備されます。

2.build-target

検査対象のプロジェクトを、AddressSanitizer、カバレッジ計測、ファザーなど、CRSが必要とする設定でビルドします。

通常のリリースビルドとは異なり、メモリ破壊や未定義動作を検出しやすい計測コードが追加されます。

3.run

準備・ビルドした対象に対して、ファザー、LLMエージェント、解析器、パッチ生成器などのCRSコンテナを実行します。

CRSは、結果を次のような成果物として提出します。

  • seed:ファジングへ与える初期入力
  • pov:問題を再現する入力、Proof of Vulnerability
  • bug-candidate:脆弱性候補の情報
  • patch:修正パッチ
  • logs:エージェントや解析処理のログ

libCRS

各CRSコンテナは、libCRSという共通CLIを利用してOSS-CRS基盤と通信します。

例えば、次のような処理を行えます。

libCRS submit pov /path/to/crash-input
libCRS submit patch /path/to/fix.diff
libCRS register-submit-dir pov /output/povs
libCRS register-log-dir /var/log/agent
libCRS download-build-output asan/build /opt/target/build

これにより、あるCRSが発見したPoVを別の修正CRSへ渡すといった構成を作れます。


現在利用できるCRS

2026年7月19日時点で、公式レジストリには43種類のCRSが掲載されています。

レジストリ:

OSS-CRS Registry

代表例は次のとおりです。

  • crs-libfuzzer
  • Atlantis C Bullseye
  • Atlantis C DeepGen
  • Atlantis Java Main
  • Atlantis Multilang
  • Claude Code Bug Finding Agent
  • Claude Code Bug Fixing Agent
  • Codex Bug Finding Agent
  • Codex Bug Fixing Agent
  • Gemini CLI Bug Finding Agent
  • Gemini CLI Bug Fixing Agent
  • Copilot CLI Bug Finding Agent
  • Google ClusterFuzz Triage
  • Atlantis Triage
  • Atlantis Ensemble
  • Harness Generation Agent

レジストリへ登録されたCRSは、Composeファイルへ名前を書くだけで参照できます。

例えば、libFuzzerを利用する基本構成は次のようになります。

run_env: local
docker_registry: local

oss_crs_infra:
  cpuset: "0-1"
  memory: "4G"

crs-libfuzzer:
  cpuset: "2-7"
  memory: "16G"

sourceを省略すると、OSS-CRSが公式レジストリから対象CRSのリポジトリと参照先を解決します。


OSS-CRSが実際に発見した未知の脆弱性

2026年3月に公開されたOSS-CRS論文では、Team Atlantaの優勝システムATLANTISをOSS-CRSへ移植し、OSS-Fuzz対象の8プロジェクトへ適用した結果、10件の未知のバグを発見し、そのうち3件が高重要度だったと報告されています。

その後、OpenSSFは2026年4月時点の累積成果として、PHP、U-Boot、memcached、Apache Ignite 3など16プロジェクトから25件の脆弱性を発見したと発表しています。

つまり、OSS-CRSは競技用のデモだけではなく、現実のオープンソースプロジェクトへ適用され始めています。

論文:

OSS-CRS: Liberating AIxCC Cyber Reasoning Systems for Real-World Open-Source Security


導入前に理解すべき重要な制約

OSS-CRSは非常に強力ですが、一般的なCLIツールのように数分で導入し、どのプロジェクトでも確実に脆弱性を発見できるものではありません。

大量のCPU・メモリを使用する

ファジングは、同じプログラムへ大量の入力を繰り返し与えます。

複数のCRS、LLM、ビルドコンテナ、データベース、LiteLLMなどを同時に動かす場合は、相応のCPUとメモリが必要です。

小規模な基本検証であれば、次の環境が現実的です。

  • CPU:8コア以上
  • メモリ:32GB以上
  • 空きディスク:100GB以上
  • OS:Ubuntu 22.04または24.04
  • アーキテクチャ:x86_64

これはOSS-CRSが公式に保証する最低構成ではなく、本記事で複数コンテナを無理なく試すための推奨構成です。

LLM利用料が発生する

libFuzzerだけを動かす基本CRSは、LLM APIキーを必要としません。

Atlantis MultilangやClaude Code、Codexなどを利用するCRSでは、モデルのAPI費用または対応サービスの利用枠が必要です。

OSS-CRSのCompose設定では、CRSごとにドル単位のLLM予算上限を設定できます。

atlantis-multilang-wo-concolic:
  cpuset: "4-11"
  memory: "24G"
  llm_budget: 20

最初は小さな予算と短いタイムアウトで動作確認し、その後段階的に増やすべきです。

ファズハーネスの品質に左右される

ファザーは、対象プログラムの入口へ入力を与える必要があります。

その入口を作るコードがファズハーネスです。

ファズハーネスが重要な処理を呼び出していなければ、どれだけ長時間実行しても対象コードへ到達しません。

AIが生成したパッチは必ず人間が確認する

OpenSSFが紹介した研究では、630件のAI生成パッチを人間が確認したところ、20~40%が意味的に誤っていました。

さらに危険なのは、これらの誤ったパッチが自動テストや機械的な検証を通過していた点です。

例えば、次のような修正が考えられます。

  • クラッシュする機能自体を無効化した
  • 入力をすべて拒否するようにした
  • 本来必要な処理を削除した
  • テストだけ通る特殊な条件を入れた
  • 別の場所へ不具合を移動させた

「ビルドが通った」「PoVで落ちなくなった」だけでは、正しい修正とは限りません。


UbuntuへOSS-CRSを導入する

ここから実際の導入手順へ進みます。

本記事では、Ubuntu 22.04または24.04のx86_64環境を前提にします。

1.基本パッケージを導入する

sudo apt update

sudo apt install -y \
  ca-certificates \
  curl \
  git \
  jq \
  build-essential \
  python3 \
  python3-venv

2.Docker公式リポジトリを追加する

sudo install -m 0755 -d /etc/apt/keyrings

sudo curl -fsSL \
  https://download.docker.com/linux/ubuntu/gpg \
  -o /etc/apt/keyrings/docker.asc

sudo chmod a+r /etc/apt/keyrings/docker.asc

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

3.Docker Engineを導入する

sudo apt update

sudo apt install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

動作確認します。

sudo docker run --rm hello-world

docker --version
docker compose version
docker buildx version

4.一般ユーザーからDockerを使えるようにする

sudo usermod -aG docker "$USER"

設定を反映するには、一度ログアウトして再ログインします。

即時反映する場合は次を実行できます。

newgrp docker

注意:dockerグループのユーザーは、実質的にroot相当の操作が可能です。信頼できる検証専用ユーザーだけを追加してください。

5.uvを導入する

uvは、高速なPythonパッケージ・実行環境管理ツールです。

スクリプトを先に確認する場合:

curl -LsSf https://astral.sh/uv/install.sh | less

問題がなければ実行します。

curl -LsSf https://astral.sh/uv/install.sh | sh

シェル設定を再読み込みします。

source "$HOME/.local/bin/env" 2>/dev/null || true
source ~/.bashrc 2>/dev/null || true

確認します。

uv --version

6.OSS-CRSを取得する

mkdir -p "$HOME/security-lab"
cd "$HOME/security-lab"

git clone https://github.com/ossf/oss-crs.git
cd oss-crs

取得したバージョンを記録します。

git rev-parse HEAD
git log -1 --oneline

依存関係を同期します。

uv sync

OSS-CRS CLIを確認します。

uv run oss-crs --help

7.Dockerの空き容量を確認する

df -h
docker system df

OSS-CRSでは複数の大きなDockerイメージとビルド成果物が作られます。

空き容量が少ないサーバーでは実行しないでください。


最初はLLMを使わずlibFuzzerを動かす

最初からAtlantisやClaude Code CRSを動かすと、問題が発生した際に、Docker、ビルド、LLM設定のどこが原因か分からなくなります。

まずはLLMを必要としないcrs-libfuzzerで基盤を確認します。

OSS-Fuzzのプロジェクト定義を取得する

OSS-CRSは、OSS-Fuzz形式のプロジェクトを対象にします。

すべてのOSS-Fuzzリポジトリを取得すると容量が大きいため、projectsディレクトリだけをSparse Checkoutします。

cd "$HOME/security-lab"

git clone \
  --depth=1 \
  --filter=blob:none \
  --no-checkout \
  https://github.com/google/oss-fuzz.git

cd oss-fuzz

git sparse-checkout init --cone
git sparse-checkout set projects
git checkout

cd ../oss-crs

libxml2の定義を確認します。

ls -la ../oss-fuzz/projects/libxml2

sed -n '1,220p' \
  ../oss-fuzz/projects/libxml2/Dockerfile

sed -n '1,260p' \
  ../oss-fuzz/projects/libxml2/build.sh

CRSを準備する

uv run oss-crs prepare \
  --compose-file ./example/crs-libfuzzer/compose.yaml

この処理では、CRSのリポジトリ・依存関係・Dockerイメージなどが準備されます。

libxml2をビルドする

uv run oss-crs build-target \
  --compose-file ./example/crs-libfuzzer/compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2

初回ビルドでは、ベースイメージ取得やソースコードのコンパイルに時間がかかります。

xmlハーネスへファジングを実行する

uv run oss-crs run \
  --compose-file ./example/crs-libfuzzer/compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2 \
  --target-harness xml \
  --timeout 300

--timeout 300は、5分で処理を終了する指定です。

5分では未知の脆弱性を発見できない可能性が高いですが、環境が正しく動くか確認するには十分です。

成果物を確認する

uv run oss-crs artifacts \
  --compose-file ./example/crs-libfuzzer/compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2 \
  --target-harness xml

新しいバージョンでは、最新実行を選択する--latestオプションも利用できます。

uv run oss-crs artifacts \
  --compose-file ./example/crs-libfuzzer/compose.yaml \
  --latest

成果物には、次のディレクトリが表示される可能性があります。

  • PoV
  • seed
  • bug candidate
  • patch
  • agent logs

実行中のDockerコンテナを確認する

docker ps

docker stats --no-stream

失敗した場合のログ確認

docker ps -a

docker logs <CONTAINER_ID>

または、OSS-CRSが生成したCompose環境のディレクトリへ移動し、次のように確認します。

docker compose ps
docker compose logs --tail=300

LLMを利用するAtlantis Multilangを動かす

libFuzzerの基本動作を確認したら、LLMを使うCRSを試します。

公式Quick Startでは、Atlantis Multilang系のCRSが例として掲載されています。

バージョンによってサンプルディレクトリ名が変わる可能性があるため、最初に確認します。

find example -maxdepth 2 \
  -type f \
  -name 'compose.yaml' \
  | grep -i atlantis

現在の公式サイトで紹介されている例:

./example/atlantis-multilang-wo-concolic/compose.yaml

APIキーを.envへ保存する

使用するLLMプロバイダーに応じて設定します。

cd "$HOME/security-lab/oss-crs"

cat > .env <<'EOF'
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
GEMINI_API_KEY=
EOF

chmod 600 .env

使用しないプロバイダーは空欄のままにせず、ComposeまたはLiteLLM設定から対象モデルを外す方が安全です。

APIキーをGitへコミットしないよう確認します。

grep -qxF '.env' .gitignore || \
  echo '.env' >> .gitignore

利用モデルを確認する

grep -RIn \
  -E 'model_name|model:|required_llms|llm_budget' \
  example/atlantis-multilang-wo-concolic \
  | head -100

モデル名が、現在契約・利用できるモデルと一致しているか確認します。

LLM予算を制限する

サンプルComposeを直接書き換えず、検証用コピーを作ります。

cp \
  ./example/atlantis-multilang-wo-concolic/compose.yaml \
  ./lab-atlantis-compose.yaml

編集します。

nano ./lab-atlantis-compose.yaml

CRSエントリへ予算上限を追加します。

atlantis-multilang-wo-concolic:
  cpuset: "4-11"
  memory: "24G"
  llm_budget: 20

これは例です。CPU番号とメモリは、自分のPC構成へ合わせて変更してください。

Atlantis CRSを準備する

uv run oss-crs prepare \
  --compose-file ./lab-atlantis-compose.yaml

対象をビルドする

uv run oss-crs build-target \
  --compose-file ./lab-atlantis-compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2

Atlantisを実行する

uv run oss-crs run \
  --compose-file ./lab-atlantis-compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2 \
  --target-harness xml \
  --timeout 1800

最初は30分程度に制限し、ログ、API消費、CPU、メモリを確認します。

docker stats

watch -n 5 'docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"'

実行後の確認

uv run oss-crs artifacts \
  --compose-file ./lab-atlantis-compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2 \
  --target-harness xml

未知の脆弱性が発見されなかったとしても、導入失敗とは限りません。

短時間で未知の脆弱性が見つからない方が普通です。

確認すべきなのは次の点です。

  • CRSが正常に起動したか
  • LLMへリクエストが送られたか
  • ハーネスまたはシードが生成されたか
  • カバレッジが増加したか
  • エージェントログが保存されたか
  • 予算上限が機能したか

Claude Codeを脆弱性発見エージェントとして動かす

OSS-CRS公式レジストリには、Claude Codeを使用する次のCRSがあります。

  • crs-bug-finding-claude-code
  • crs-claude-code
  • crs-harness-gen-claude-code

Claude CodeのOAuthトークンを使う場合、APIキーを直接設定せずに認証できます。

Claude Codeを認証する

claude setup-token

表示されたトークンを環境変数へ設定します。

export CLAUDE_CODE_OAUTH_TOKEN='取得したトークン'

.envへ保存する場合:

cat >> .env <<'EOF'
CLAUDE_CODE_OAUTH_TOKEN=取得したトークン
EOF

chmod 600 .env

Claude Code Bug Finding CRSを準備する

uv run oss-crs prepare \
  --compose-file \
  ./example/crs-bug-finding-claude-code/compose.yaml

対象をビルドする

uv run oss-crs build-target \
  --compose-file \
  ./example/crs-bug-finding-claude-code/compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2

脆弱性発見エージェントを実行する

uv run oss-crs run \
  --compose-file \
  ./example/crs-bug-finding-claude-code/compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2 \
  --target-harness xml \
  --timeout 1800

成果物を取得する

uv run oss-crs artifacts \
  --compose-file \
  ./example/crs-bug-finding-claude-code/compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2 \
  --target-harness xml

Claude Code CRSが提出したbug candidate、PoV、ログなどを確認します。


Claude Codeをパッチ生成エージェントとして動かす

バグ修正CRSでは、パッチを何度も適用して再ビルドするため、インクリメンタルビルドが重要です。

OSS-CRSには、ビルド済みの対象をDockerスナップショットとして保存し、パッチ部分だけを再ビルドする仕組みがあります。

修正CRSを準備する

uv run oss-crs prepare \
  --compose-file ./example/crs-claude-code/compose.yaml

インクリメンタルビルド用に対象を構築する

uv run oss-crs build-target \
  --compose-file ./example/crs-claude-code/compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2 \
  --incremental-build

PoVを指定して修正CRSを実行する

先ほどのバグ発見CRSが出力したPoVディレクトリを確認します。

以下では例として/path/to/povsとしています。

uv run oss-crs run \
  --compose-file ./example/crs-claude-code/compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2 \
  --target-harness xml \
  --pov-dir /path/to/povs \
  --incremental-build \
  --timeout 1800

生成されたパッチを確認する

uv run oss-crs artifacts \
  --compose-file ./example/crs-claude-code/compose.yaml \
  --fuzz-proj-path ../oss-fuzz/projects/libxml2 \
  --target-harness xml

パッチファイルが出力されても、直ちに本番コードへ適用してはいけません。

必ず次を確認します。

git apply --stat generated.patch
git apply --check generated.patch
cat generated.patch

隔離した作業ブランチで適用します。

git switch -c review/oss-crs-generated-patch

git apply generated.patch

git diff --check
git diff

その後、プロジェクト固有のテスト、既存ファズハーネス、PoV再現、機能テストを実施します。


完全ローカルの脆弱なサンプルを作る

既存のオープンソースプロジェクトでは、短時間でクラッシュが見つかるとは限りません。

そこで、OSS-CRSの仕組みを理解するため、意図的に単純なメモリ破壊を含むローカル専用サンプルを作ります。

以下のサンプルは学習用です。外部公開サーバーへ配置せず、隔離した検証環境だけで使用してください。

ディレクトリを作る

cd "$HOME/security-lab/oss-crs"

mkdir -p \
  lab/toy-parser/include \
  lab/toy-parser/src \
  lab/toy-parser/fuzz \
  lab/toy-oss-fuzz

ヘッダーファイル

cat > lab/toy-parser/include/toy_parser.h <<'EOF'
#ifndef TOY_PARSER_H
#define TOY_PARSER_H

#include <stddef.h>
#include <stdint.h>

int toy_parse(const uint8_t *data, size_t size);

#endif
EOF

意図的に脆弱なパーサー

cat > lab/toy-parser/src/toy_parser.c <<'EOF'
#include "toy_parser.h"

#include <string.h>

int toy_parse(const uint8_t *data, size_t size)
{
    static const char magic[] = "OSSCRS";

    if (data == NULL || size < sizeof(magic) - 1) {
        return 0;
    }

    if (memcmp(data, magic, sizeof(magic) - 1) != 0) {
        return 0;
    }

    /*
     * 学習用に意図的なスタックバッファオーバーフローを入れている。
     * "OSSCRS" に続く入力が8バイトを超えると small を破壊する。
     */
    char small[8];
    size_t payload_size = size - (sizeof(magic) - 1);

    memcpy(
        small,
        data + (sizeof(magic) - 1),
        payload_size
    );

    return (int)small[0];
}
EOF

libFuzzer用ハーネス

cat > lab/toy-parser/fuzz/fuzz_toy_parser.cc <<'EOF'
#include <cstddef>
#include <cstdint>

extern "C" {
#include "toy_parser.h"
}

extern "C" int LLVMFuzzerTestOneInput(
    const uint8_t *data,
    size_t size
) {
    toy_parse(data, size);
    return 0;
}
EOF

OSS-Fuzz形式のDockerfile

cat > lab/toy-oss-fuzz/Dockerfile <<'EOF'
FROM gcr.io/oss-fuzz-base/base-builder

WORKDIR $SRC/toy-parser

COPY build.sh $SRC/
EOF

build.shを作る

cat > lab/toy-oss-fuzz/build.sh <<'EOF'
#!/bin/bash

set -euxo pipefail

$CC $CFLAGS \
  -I"$SRC/toy-parser/include" \
  -c "$SRC/toy-parser/src/toy_parser.c" \
  -o /tmp/toy_parser.o

$CXX $CXXFLAGS \
  -I"$SRC/toy-parser/include" \
  "$SRC/toy-parser/fuzz/fuzz_toy_parser.cc" \
  /tmp/toy_parser.o \
  $LIB_FUZZING_ENGINE \
  -o "$OUT/toy_parser_fuzzer"
EOF

chmod +x lab/toy-oss-fuzz/build.sh

構成を確認する

find lab -maxdepth 4 -type f -print

次の構成になっていれば準備完了です。

lab/
├── toy-parser/
│   ├── include/
│   │   └── toy_parser.h
│   ├── src/
│   │   └── toy_parser.c
│   └── fuzz/
│       └── fuzz_toy_parser.cc
└── toy-oss-fuzz/
    ├── Dockerfile
    └── build.sh

ローカルサンプルをOSS-CRSでビルドする

OSS-CRSでは、OSS-Fuzz形式のプロジェクト定義と、対象の実ソースコードを別々に指定できます。

--fuzz-proj-pathへDockerfileとbuild.shを指定し、--target-source-pathへ実際のソースを指定します。

CRSを準備する

uv run oss-crs prepare \
  --compose-file ./example/crs-libfuzzer/compose.yaml

サンプルをビルドする

uv run oss-crs build-target \
  --compose-file ./example/crs-libfuzzer/compose.yaml \
  --fuzz-proj-path ./lab/toy-oss-fuzz \
  --target-source-path ./lab/toy-parser

ファザーを実行する

uv run oss-crs run \
  --compose-file ./example/crs-libfuzzer/compose.yaml \
  --fuzz-proj-path ./lab/toy-oss-fuzz \
  --target-source-path ./lab/toy-parser \
  --target-harness toy_parser_fuzzer \
  --timeout 300

このサンプルでは、OSSCRSという6バイトの接頭辞を発見し、その後ろへ8バイトを超える入力が続くとAddressSanitizerがスタックバッファオーバーフローを検出します。

ファジングはランダム入力だけではありません。

入力の変化と新しく通過したコード経路を記録し、カバレッジが増える方向へ入力を変化させます。

成果物を確認する

uv run oss-crs artifacts \
  --compose-file ./example/crs-libfuzzer/compose.yaml \
  --fuzz-proj-path ./lab/toy-oss-fuzz \
  --target-harness toy_parser_fuzzer

PoVが生成された場合は、対象ファイルのサイズと16進表現を確認します。

ls -lah /path/to/povs

xxd /path/to/povs/<POV_FILE> | head -50

PoVには、ファザーがクラッシュを再現するために生成した入力が保存されています。


サンプルの脆弱性を人間が修正する

意図的な脆弱性は、入力サイズを確認せず固定長バッファへコピーしていることです。

修正例:

python3 - <<'PY'
from pathlib import Path

path = Path("lab/toy-parser/src/toy_parser.c")
text = path.read_text()

old = """    memcpy(
        small,
        data + (sizeof(magic) - 1),
        payload_size
    );
"""

new = """    if (payload_size > sizeof(small)) {
        return -1;
    }

    memcpy(
        small,
        data + (sizeof(magic) - 1),
        payload_size
    );
"""

if old not in text:
    raise SystemExit("修正対象が見つかりません")

path.write_text(text.replace(old, new))
PY

差分を確認します。

git diff --no-index \
  /dev/null \
  lab/toy-parser/src/toy_parser.c \
  || true

再ビルドします。

uv run oss-crs build-target \
  --compose-file ./example/crs-libfuzzer/compose.yaml \
  --fuzz-proj-path ./lab/toy-oss-fuzz \
  --target-source-path ./lab/toy-parser

再実行します。

uv run oss-crs run \
  --compose-file ./example/crs-libfuzzer/compose.yaml \
  --fuzz-proj-path ./lab/toy-oss-fuzz \
  --target-source-path ./lab/toy-parser \
  --target-harness toy_parser_fuzzer \
  --timeout 300

修正前に生成されたPoVも再実行し、同じクラッシュが発生しないことを確認します。

ただし、「クラッシュしなくなった」だけでは不十分です。

この修正では、8バイトより長いデータを拒否しています。

本来の仕様が「長いデータを切り詰めて読み込む」のであれば、この修正は意味的に誤っています。

正しい修正は、製品仕様に応じて次のいずれかになる可能性があります。

  • 長い入力をエラーにする
  • 必要なサイズのメモリを動的確保する
  • 最大8バイトだけコピーする
  • 入力フォーマット自体を変更する

これが、AI生成パッチを人間がレビューしなければならない理由です。


ローカルサンプルをClaude Code CRSへ修正させる

次に、同じサンプルをClaude Codeの修正CRSへ渡す構成を考えます。

修正用ビルドを作る

uv run oss-crs prepare \
  --compose-file ./example/crs-claude-code/compose.yaml

uv run oss-crs build-target \
  --compose-file ./example/crs-claude-code/compose.yaml \
  --fuzz-proj-path ./lab/toy-oss-fuzz \
  --target-source-path ./lab/toy-parser \
  --incremental-build

PoVディレクトリを指定する

uv run oss-crs run \
  --compose-file ./example/crs-claude-code/compose.yaml \
  --fuzz-proj-path ./lab/toy-oss-fuzz \
  --target-source-path ./lab/toy-parser \
  --target-harness toy_parser_fuzzer \
  --pov-dir /path/to/povs \
  --incremental-build \
  --timeout 1800

出力されたパッチを確認する

uv run oss-crs artifacts \
  --compose-file ./example/crs-claude-code/compose.yaml \
  --fuzz-proj-path ./lab/toy-oss-fuzz \
  --target-harness toy_parser_fuzzer

生成パッチへ対し、最低限次を評価します。

  • 脆弱性の原因を正しく理解しているか
  • 境界条件が正しいか
  • 別の整数オーバーフローを作っていないか
  • 必要な機能を無効化していないか
  • PoVが再現しなくなったか
  • 正常入力が引き続き処理されるか
  • ファジングを継続して新しいクラッシュがないか

OSS-CRSの結果をどう評価すべきか

PoVが出た

PoVが出力された場合、実際にクラッシュを再現できるか確認します。

一度だけ発生した不安定なクラッシュや、ビルド環境固有の問題である可能性もあります。

バグ候補だけが出た

LLMや静的解析が怪しいコードを見つけても、再現入力を生成できていない状態です。

ただちに脆弱性と断定せず、コードレビュー、追加ハーネス、指向性ファジングが必要です。

パッチが出た

パッチが出ても、正しい修正とは限りません。

次の四段階で評価します。

  1. Build correctness:ビルドできるか
  2. PoV correctness:既知PoVを止められるか
  3. Regression correctness:既存機能を壊していないか
  4. Semantic correctness:本来の仕様を満たしているか

何も出なかった

何も発見されない理由は複数あります。

  • 対象に脆弱性がない
  • ハーネスが重要な処理へ到達していない
  • シードが不足している
  • 実行時間が短い
  • 必要な辞書がない
  • 対象プロトコルが複雑
  • LLMが正しい解析方針を立てられなかった
  • ビルド設定が実運用と異なる

「発見ゼロ」は安全証明ではありません。


WordPressやPHPへOSS-CRSを使えるのか

OpenSSFは、OSS-CRSによってPHPを含む複数プロジェクトから脆弱性が発見されたと報告しています。

ただし、一般的なWordPressサイトへそのまま適用できるわけではありません。

適用しやすいPHP対象

  • 独自パーサー
  • ファイル変換ライブラリ
  • 画像処理
  • CSV・XML・JSON処理
  • 圧縮・解凍処理
  • テンプレート解析
  • PHP拡張
  • 入力を関数へ直接渡せるライブラリ

適用が難しい対象

  • 複雑なWordPress管理画面全体
  • 外部APIへ強く依存するプラグイン
  • データベース状態が複雑な業務機能
  • ブラウザ操作を必要とする画面
  • 多数のプラグインが相互作用する環境

WordPressでは、OSS-CRSだけでなく次の組み合わせが必要です。

  • PHPStanまたはPsalm
  • Composer Audit
  • OSV-Scanner
  • WordPress Coding Standards
  • PHPUnit
  • Playwright
  • DAST
  • ファジング
  • 人間によるコードレビュー

企業で使う場合の推奨運用

1.検証環境を分離する

OSS-CRSを、本番サーバー上で直接実行してはいけません。

専用のUbuntuサーバー、クラウドVM、または検証用ワークステーションを用意します。

2.本番用秘密情報を置かない

  • SSH秘密鍵
  • 本番DBパスワード
  • クラウド管理者キー
  • 顧客データ
  • 本番Cookie

CRSコンテナやLLMへ、本来不要な秘密情報を渡さないようにします。

3.外部LLMへ送信される内容を確認する

LLM型CRSは、対象コードや解析結果を外部APIへ送信する可能性があります。

機密ソースコードを扱う場合は、契約、データ保持、学習利用、リージョン、ログ保存などを確認してください。

4.予算とタイムアウトを制限する

初期検証では、短時間・少額に制限します。

llm_budget: 10
--timeout 600

5.AIパッチを自動マージしない

AI生成パッチは、必ずPull Requestとして提出させます。

自動マージは禁止し、人間によるレビュー、テスト、ステージング確認を必須にします。

6.責任ある開示を行う

第三者のオープンソースプロジェクトから未知の脆弱性を発見した場合、公開Issueへ詳細を投稿してはいけません。

対象プロジェクトのSECURITY.md、GitHub Security Advisory、専用メールアドレスなど、非公開の報告経路を利用します。


CI/CDへ組み込む場合の考え方

OSS-CRSをすべてのコミットで長時間動かすのは現実的ではありません。

次のように役割を分ける構成が有効です。

Pull Requestごと

  • 数分のlibFuzzer
  • 変更箇所周辺のハーネス
  • 既知PoVの再現防止
  • AddressSanitizer
  • UndefinedBehaviorSanitizer

毎晩

  • 30分~数時間のファジング
  • LLMによるバグ候補探索
  • 新規シード生成

毎週

  • 複数CRSによるEnsemble
  • 長時間ファジング
  • AIパッチ候補生成
  • 人間によるトリアージ

リリース前

  • 既知PoV全件の再実行
  • 回帰テスト
  • 長時間ファジング
  • 生成パッチの意味的レビュー

ディスク容量を整理する

OSS-CRSを繰り返し実行すると、Dockerイメージとビルド成果物が増えます。

使用状況を確認します。

docker system df -v

OSS-CRSには、過去の実行成果物やDockerリソースを整理するcleanコマンドがあります。

uv run oss-crs clean --help

削除対象を確認してから実行します。

uv run oss-crs clean

成果物まで削除する場合は、現在のバージョンのヘルプを確認したうえで--artifactsを使用します。

PoV、パッチ、調査ログを保存する必要がある場合は、削除前に別ディレクトリへ退避してください。


よくあるエラーと対処方法

Docker permission denied

permission denied while trying to connect to the Docker daemon socket

dockerグループへの追加が反映されていない可能性があります。

groups
ls -l /var/run/docker.sock

再ログイン後に確認します。

CPUセットが存在しない

Composeのcpusetで、実際に存在しないCPU番号を指定すると起動できません。

nproc
lscpu

4コア環境で4-7を指定しないよう注意します。

メモリ不足

docker stats
free -h
dmesg | grep -i -E 'oom|killed process'

Composeのmemory値と並列CRS数を減らします。

LLMモデルが見つからない

LiteLLM設定のモデル名と、CRSが要求するモデル名が一致しているか確認します。

grep -RIn \
  -E 'required_llms|model_name|model:' \
  example \
  | head -200

GLIBCバージョンエラー

ビルド環境と実行環境のOSが異なると、次のようなエラーが発生する可能性があります。

version `GLIBC_2.xx' not found

独自CRSを作る場合は、固定のbase-runnerではなく、OSS-CRSが提供するbase_runner_imageを利用します。

ファザーがすぐ終了する

  • ハーネス名が間違っている
  • build.shがOUTへバイナリをコピーしていない
  • ソースコードのWORKDIRが間違っている
  • LIB_FUZZING_ENGINEをリンクしていない
  • サニタイザーと対象言語が一致していない

OSS-CRSはセキュリティ技術者を不要にするのか

現時点では、逆です。

OSS-CRSのような技術が普及すると、セキュリティ技術者には次の仕事がより重要になります。

  • どのコードを優先して解析するか決める
  • 良いファズハーネスを設計する
  • AIのバグ候補をトリアージする
  • クラッシュが実際に脆弱性か判断する
  • 生成パッチが仕様を守っているか確認する
  • 責任ある開示を行う
  • 自動化された解析基盤を安全に運用する

AIが大量の候補を出せるようになるほど、誤検知、重複報告、意味的に誤ったパッチも増える可能性があります。

人間の役割は「すべて手作業で探す」ことから、AIと解析ツールが出した結果を評価し、安全に実運用へつなげることへ変わっていくでしょう。


OSS-CRSの本当の革新性

OSS-CRSの価値は、「AIが脆弱性を一件発見した」という話だけではありません。

これまで、脆弱性発見ツールはそれぞれ別の形式、別の入出力、別の実行環境を持っていました。

OSS-CRSは、次の異なる役割を共通の基盤上へ載せようとしています。

  • ファザー
  • シード生成AI
  • ハーネス生成AI
  • 静的解析
  • 脆弱性候補抽出AI
  • PoV生成
  • トリアージ
  • パッチ生成AI
  • パッチ選択Ensemble
  • 回帰検証

今後、単一の巨大AIがすべてを行うのではなく、複数のCRSを組み合わせたセキュリティパイプラインが主流になる可能性があります。

あるCRSはコードレビューが得意、別のCRSはファジングが得意、別のCRSはパッチ生成が得意という構成です。

OSS-CRSは、その競争と組み合わせを可能にする基盤です。


まとめ

OSS-CRSは、LLMと従来型のセキュリティ解析技術を組み合わせ、ソフトウェアの脆弱性発見・再現・修正を自動化するCyber Reasoning Systemを、ローカルや共通環境で動かすためのOpenSSFプロジェクトです。

DARPA AI Cyber Challengeでは、Team AtlantaのATLANTISが優勝し、競技全体でも多数の合成脆弱性と実在する未知脆弱性が発見されました。

その成果が、研究室や競技専用クラウドだけで終わらず、一般のOSS開発者や企業が利用できる形へ移行し始めています。

OSS-CRSで重要なのは、次の点です。

  • 単なるLLMコードレビューではない
  • ファジングやサニタイザーとAIを統合する
  • OSS-Fuzz形式の対象を共通基盤で扱える
  • 複数のCRSを組み合わせられる
  • Claude CodeやCodexもCRSとして利用できる
  • 発見・PoV・トリアージ・修正をつなげられる
  • LLM予算とCPU・メモリを制限できる

一方、AI生成パッチをそのまま信用することはできません。

自動検証を通過しながら意味的に誤ったパッチが存在するため、最終的には人間による仕様確認、コードレビュー、回帰テストが必要です。

最も現実的な導入順は次のとおりです。

  1. 専用Ubuntu環境を用意する
  2. crs-libfuzzerで基盤を確認する
  3. ローカルの意図的に脆弱なサンプルを動かす
  4. PoVの生成と修正後の再検証を理解する
  5. LLM予算を制限してAtlantis系CRSを試す
  6. Claude CodeやCodexの発見・修正CRSを試す
  7. 自社ライブラリ用のファズハーネスを作る
  8. 人間のレビューを含むCI/CDへ組み込む

AIは、まだ単独で信頼できるセキュリティ担当者ではありません。

しかし、ファジング、静的解析、動的解析、LLM、パッチ生成、人間のレビューを一つの流れへ統合できれば、これまで人手では検査しきれなかった巨大なコードベースへ、継続的な脆弱性探索を行える可能性があります。

「AIがコードを書く時代」の次に来るのは、「AIがコードを壊し、弱点を証明し、修正案を作り、人間がその正しさを審査する時代」です。

OSS-CRSは、その未来を先取りする最も重要なオープンソース基盤の一つになる可能性があります。


参考資料

本記事は2026年7月19日時点で公開されている公式ドキュメントを基にしています。OSS-CRSは開発が活発で、Composeファイル名、登録CRS、CLIオプション、必要モデルなどが変更される可能性があります。実行時は必ず公式README、CHANGELOG、各CRSの設定ファイルを確認してください。

ABOUT ME
Yuusuke
業務システムの要件定義・設計・実装を担当。Python、PHP、JavaScript、VBA、Oracle、MySQLなど、実務と個人開発で検証した内容を発信しています。