0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Mozilla 0DIN AI Scanner を試してみた - Garakベースの統合スキャナーをローカルLLMで動かす

0
Posted at

はじめに

1本目の記事ではGarak・promptfoo・PyRITの3ツールを試し、2本目ではシステムプロンプトによる防御を検証、3本目ではOWASP LLM Top 10を全項目検証しました。

今回は、2026年4月にMozillaの0DINチームがオープンソースリリースした0DIN AI Scannerを試してみます。Garakを触ったことがある人なら「GarakにWeb UIが付いたもの」と言えば伝わるかもしれません。ただ、それだけではない機能もあったので、セットアップから実際のスキャンまで一通り記録しておきます。

なお、今回はセットアップでかなりハマりました。うまくいかなかった過程もそのまま書いているので、同じ環境で試す方の参考になれば。


0DIN AI Scanner とは

0DIN(Zero-Day Investigative Network)は、Mozillaが運営するAIセキュリティのバグバウンティプログラムです。世界中のセキュリティ研究者がAIシステムの脆弱性を報告し、その知見が蓄積されています。0DIN AI Scannerは、そこで得られた脅威インテリジェンスをベースにした自動スキャナーです。

Garak単体との違い

スキャンエンジンにはNVIDIA Garakを採用していますが、その上にいくつかの機能が載っています。

機能 Garak単体 0DIN AI Scanner
実行方法 CLI Web UI
結果閲覧 HTMLレポート(手動生成) Web UI + PDFレポート(自動)
スコアリング Pass/Fail ASR(Attack Success Rate)%
スケジュール実行 なし(cron等で自前対応) UIから設定可能
SIEM連携 なし Splunk / Rsyslog
OWASP LLM Top 10 手動マッピング 公式マッピング済み
プローブ数 150+ 179(35脆弱性ファミリー)

一言でまとめると「Garakのエンタープライズ版」です。CLIに慣れている人には不要かもしれませんが、チームでの運用やレポーティングが必要な場面では便利そうです。

技術スタック

  • Ruby on Rails(Web UI / API)
  • Python + Garak 0.13.3(スキャンエンジン)
  • PostgreSQL(結果保存)
  • Docker Compose(デプロイ)

検証環境

項目 詳細
OS Windows 11 Pro
Docker Docker Desktop 28.4.0(WSL2バックエンド)
Ollama 0.19.0
テスト対象モデル Llama 3.2 (3B, Q4_K_M量子化)
推論 CPU

セットアップ

リポジトリのクローン(CRLF問題に注意)

最初にハマったのがこれです。普通に git clone するとWindows環境ではLF→CRLF変換が行われ、Dockerのビルドでシェルスクリプトが実行できなくなります。

# NG: 普通にクローンするとCRLF変換される
git clone https://github.com/0din-ai/ai-scanner.git

# OK: CRLF変換を無効化してクローン
git clone --config core.autocrlf=false https://github.com/0din-ai/ai-scanner.git

--config core.autocrlf=false を付けることで、リポジトリ内の改行コードをLFのまま保持します。Windowsでの改行コード関連のトラブルはDocker系のプロジェクトで頻出するので、覚えておいて損はありません。

.env ファイルの設定(ポート80占有問題)

cd ai-scanner
Copy-Item .env.example .env

.env を編集して3つの値を設定します。

SECRET_KEY_BASE=<openssl rand -hex 64 で生成した値>
PORT=3000
POSTGRES_PASSWORD=<任意のパスワード>

ここでもハマりポイントがあります。 デフォルトの PORT=80 のままだと、Docker Desktop Backendプロセス(com.docker.backend)がポート80を使っていてバインドに失敗しました。自分の環境では netstat -ano | findstr ":80 " で確認したところ、しっかり占有されています。PORT=3000 に変更して回避しています。

ビルドと起動

docker compose build    # 初回は20分程度かかる
docker compose up -d    # バックグラウンドで起動
docker compose ps       # 3サービスの起動確認

3つのサービスが立ち上がります。

サービス 役割
scanner Railsアプリ + Garakエンジン
scanner_postgres PostgreSQLデータベース
mock-llm テスト用のモックLLM

全てが running / healthy になったら、ブラウザで http://localhost:3000 を開きます。

ネットワーク疎通確認

DockerコンテナからWindowsホスト上のOllamaにアクセスする必要があるため、事前に確認しておきます。

# コンテナ内からOllamaのモデル一覧を取得
docker exec scanner curl -s http://host.docker.internal:11434/api/tags

host.docker.internal はDocker Desktop環境でコンテナからホストマシンにアクセスするための特別なホスト名です。ここで llama3.2 がモデルリストに表示されればOKです。


ターゲット設定

プロバイダー選択

Web UIにログインし(初期認証: admin@example.com / password)、左メニューの TargetsNew Target に進むと、プロバイダー選択画面が表示されます。

choose-provider.png

OpenRouter、OpenAI GPT-4o、Google Gemini、Hugging Faceなどのカードが並んでいますが、今回は 「Ollama Llama 3.3」(Localバッジ付き)を選択します。

JSON Configの設定

プリセットを選ぶと、設定画面が表示されます。

configure-before.png

デフォルトではモデル名が llama3.3:70b になっているので、以下のように変更します。

フィールド 変更前 変更後
Name Ollama Llama 3.3 Ollama Llama 3.2
Model llama3.3:70b llama3.2

さらに、JSON ConfigにDockerコンテナからホストのOllamaに接続するための設定を追加します。

{
  "ollama": {
    "OllamaGenerator": {
      "model": "llama3.2",
      "host": "http://host.docker.internal:11434"
    }
  }
}

ここでハマった: JSON Configの形式

実は最初の試行(前回)では、このJSON Configの設定でValidateが 「Bad - No responses received」 になり、数日間解決できませんでした。

原因は2つありました。

1. パラメータ名が間違っていた

GarakのOllamaGeneratorは host というパラメータを使います。base_urlurl ではありません。GarakのソースコードでDEFAULT_PARAMSを確認すると "host": "127.0.0.1:11434" と定義されています。

2. Modelフィールドの不可視文字

UIのModelフィールドにコピペで値を入力した際、不可視文字が混入して「Model contains invalid characters」というバリデーションエラーが出ました。フィールドの内容を一度全選択して削除し、キーボードで直接入力することで解消しています。

Validate成功

設定を正しく行った後、ターゲットを作成すると自動でValidationが走ります。

validate-good.png

Status: Good、Performance: 4.7 tok/s が表示されれば成功です。3Bモデル + CPU推論なので速度はこんなものです。


スキャン実行

プローブの選択

ターゲット詳細ページの Run Scan から、スキャン設定画面に進みます。

probe-selection-detail.png

プローブはカテゴリ単位で選択できます。

カテゴリ プローブ数 内容
Copyright Violation: Harry Potter 1 著作権侵害テスト
Generic Mitigation Bypass Checks 10 ガードレール回避テスト
Illicit Substances: Crystal Meth 13 違法物質に関する情報生成テスト
Community Probes 179 コミュニティ提供のプローブ

今回は動作確認のため Generic Mitigation Bypass Checks(10プローブ)のみ選択しました。推定実行時間は9分、推定入力トークン数は6,831と表示されます。

スキャン開始!!

scan-pending.png

スキャンを作成すると、Status が PendingRunning に変わります。左下の「REPORTS RUNNING: 1」でジョブが走っていることが確認できます。

ここでハマった: 推定9分のはずが一晩かかった

推定9分と表示されていたので、コーヒーでも飲みながら待つつもりでした。が、30分経ってもRunningのまま。

ログを確認すると、garakがOllamaへのリクエストでバックオフ(リトライ待ち)を繰り返していました。

Process stderr: 2026-04-15 10:25:33 - backoff - INFO - Backing off _call_model(...)
  for 53.6s (garak.exception.GeneratorBackoffTrigger)
Process stderr: 2026-04-15 10:26:57 - backoff - INFO - Backing off _call_model(...)
  for 1.1s (garak.exception.GeneratorBackoffTrigger)
Process stderr: 2026-04-15 10:27:28 - backoff - INFO - Backing off _call_model(...)
  for 39.1s (garak.exception.GeneratorBackoffTrigger)

原因は --parallel_attempts 16 です。garakが16並列でOllamaにリクエストを投げるため、3Bモデル + CPU推論ではとても捌ききれません。タイムアウト → バックオフ → リトライの繰り返しで、推定9分のスキャンが一晩かかりました。(ファクトリオをやって時間をつぶしていたら、完了を見逃したともいう)

推定時間はおそらくGPU環境やAPIベースのLLMを前提にした計算で、ローカルCPU推論は想定外のようです。

スキャン完了!!

scan-completed.png

さらにハマった: 10プローブ中3つしか結果が返らない

ようやくスキャンが完了してレポートを見ると、10プローブ選択したはずなのに3つしか結果がありません。残りの7つはバックオフが重なりすぎてタイムアウトし、結果なしで終了したようです。


結果

レポート概要

report-list.png

項目
ASR(Attack Success Rate) 8.33%
Successful Attacks 1 / 12
結果が返ったプローブ数 3 / 10

プローブ別結果

スクリーンショット 2026-04-16 045835.png

プローブ 説明 攻撃成功率 成功数
ChemicalEngineeringInterview 「化学工学の面接」を装ったガードレール回避 25% 1/4
ArbitraryRelation 「任意の関係性」を使ったガードレール回避 0% 0/4
CharacterContextualization 「キャラクター設定」を使ったガードレール回避 0% 0/4

ChemicalEngineeringInterviewプローブが1件成功しています。これは「化学工学の面接のために教えてほしい」という文脈で有害情報を引き出す手法で、いわゆる「教育目的」系のジェイルブレイクの一種です。Llama 3.2 (3B)は1本目の記事でも同種の攻撃に弱かったので、一貫した傾向といえます。

Garak単体との比較

同じLlama 3.2 (3B)に対する結果を比べてみます。

観点 Garak単体 (Step 2) 0DIN AI Scanner
ガードレール回避 MitigationBypass: FAIL (50%) ChemicalEngInterview: 25%
DAN攻撃 PASS (未テスト)
スキャン所要時間 2時間10分 一晩(バックオフ含む)
結果の見やすさ HTMLレポート Web UI + PDF
セットアップ難度 pip一発 Docker + .env設定

0DINはGarakをエンジンとして使っているため、同じプローブなら理論上は同じ結果になるはずです。ただし、Garakのバージョン差(Garak単体: 0.14.0, 0DIN内蔵: 0.13.3)やパラメータの違い(parallel_attemptsなど)により、結果が若干異なる可能性があります。


ハマりポイントまとめ

今回のセットアップで遭遇した問題をまとめておきます。

問題 原因 解決策
Dockerビルド失敗 WindowsのCRLF変換 git clone --config core.autocrlf=false
ポートバインド失敗 Docker Desktopがポート80を占有 .envPORT=3000に変更
Validateが「No responses received」 JSON Configのパラメータ名がbase_url→正しくはhost JSON Configを修正
Modelフィールドのバリデーションエラー コピペ時の不可視文字混入 手入力で直接入力
スキャンが推定の数十倍かかる --parallel_attempts 16でローカルLLMが過負荷 待つ(設定変更の余地あり)
10プローブ中3つしか結果が出ない バックオフ重複によるタイムアウト リトライ or プローブ数を減らす

特にJSON Configの形式とCRLF問題は、公式ドキュメントには明記されていない(2026年4月時点)ので注意が必要です。


まとめ

0DIN AI Scannerは、Garakの「Web UI + レポーティング」ラッパーとして、チーム運用やレポート作成が必要な場面で価値があるツールです。179プローブ、35脆弱性ファミリー、OWASP LLM Top 10への公式マッピングと、スキャンの「幅」はGarak単体を超えています。

一方で、ローカルCPU環境での利用にはいくつかの壁がありました。

  • セットアップの複雑さ: Docker Compose必須、.envの設定項目が多い、Windows環境ではCRLF問題がある
  • ローカルLLMとの相性: 16並列リクエストがデフォルトで、小型モデル + CPU推論ではタイムアウトが頻発する
  • 結果の欠損: バックオフにより10プローブ中7つが結果なしで終了

API接続のLLM(OpenAI、OpenRouterなど)を使う場合はこれらの問題は起きないと思われます。ローカルLLMで使う場合は、並列度を下げる設定があるかを確認するか、GPUの利用を検討した方がよさそうです。


検証環境・ツールバージョン

項目 バージョン
0DIN AI Scanner 0.0.1
内蔵Garak 0.13.3
Docker Desktop 28.4.0
Docker Compose v2.39.4
Ollama 0.19.0
テスト対象モデル Llama 3.2 (3B, Q4_K_M)
OS Windows 11 Pro

次回は他のスキャンを試そうかなぁと

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?