新しい攻撃の発見: GarakとPyRIT

回帰テストは既知の失敗の再発を防ぐのに強力ですが、まだテストケースがない攻撃は発見できません。GarakとPyRITは、LLMやAIアプリケーションに対して様々なプローブと会話戦略を試行し、予期せぬ失敗候補を収集するAIレッドチームツールです。

これら2つのツールは「自動脆弱性確定器」ではありません。結果は検出器とスコアラーの判定であり、誤検知(False Positive)が発生する可能性があります。この演習では、自身が所有するローカルのテストターゲット、合成データ、および読み取り専用機能のみを使用します。発見された結果は、人間がトレースとポリシーを確認した後にのみ、脆弱性または回帰テストケースに昇格されます。

体系的な多重プローブと適応型分岐探索が保護されたLLMを検査し、発見候補を隔離保存する様子

GarakとPyRITの違い

Garakは、様々なプローブをターゲットジェネレーターに送り、検出器で失敗の兆候を探すスキャナー型のツールです。PyRIT(Python Risk Identification Tool)は、ターゲット、アタック、コンバーター、スコアラー、メモリを組み合わせて、単一ターンまたは複数ターンの攻撃実験を作成するフレームワークに近いものです。

比較 Garak PyRIT
— — —
中心単位 プローブと検出器 アタック・ターゲット・スコアラー・メモリ
強み 広範囲の繰り返しスキャン 状態を持つ適応型・多重ターン実験
ターゲット接続 ジェネレータープラグイン プロンプトターゲット
判定 検出器と評価器 スコアラーと人間によるレビュー
結果 ログ・JSONL・レポート メモリに会話・スコア・結果を保存
推奨される出発点 選択したプローブファミリーの狭いスキャン 単一の合成目的を単一ターンから実行

Garakの公式ドキュメントでは、プローブは失敗を誘発する入力と相互作用を管理し、ジェネレーターはモデルまたは会話システムへの接続をラップします。検出器は応答から特定の失敗の兆候を探し、ハーネスが全体の実行を調整します。

PyRITの公式ドキュメントでは、自動・人間主導のレッドチーム、様々なターゲット、シングルターン・マルチターン攻撃、柔軟なスコアリング、SQLite・Azure SQLベースのメモリを主要な構成要素として説明しています。

安全な実習境界の確立

Garak·PyRIT Container
  ↓ 허용된 Test Network만
Local Guardrail Gateway
  ↓
합성 Test Tenant + 읽기 전용 RAG + Mock Tool
  ↓
Nova·NeMo·Presidio → Test LLM
  ↓
비민감 Trace와 격리된 결과 저장소

実際の運用エンドポイント、他人のモデル、外部サービス、実データを対象に実行しないでください。テストゲートウェイはエグレスをブロックし、ツールはファイルの削除、コマンドの実行、支払い、メッセージの送信の代わりに、固定されたモック応答のみを返します。APIキーはイメージやノートブックに含めず、シークレットとして注入してください。

実習1: Garakの構造とインストール確認

公式リポジトリはPyPIインストールとプローブリストの確認方法を提供しています。運用評価では、検証済みのバージョンを固定します。

mkdir llm-redteam-lab
cd llm-redteam-lab

python3 -m venv .venv-garak
source .venv-garak/bin/activate
python -m pip install --upgrade pip
python -m pip install garak

python -m garak --version
python -m garak --list_probes

最初からすべてのプローブを実行すると、コスト・時間・結果量が急増します。まずテストジェネレーターで実行構造を確認するか、サービス目的に関連するプローブファミリーを1つだけ選択します。

python -m garak 
  --target_type test.Repeat 
  --probes encoding

test.Repeatは入力を繰り返す組み込みのテストターゲットです。これは実際の脆弱性を評価するコマンドではなく、インストールとレポートパイプラインを確認するための安全なスモークテストです。Garakは実行詳細をJSONLに残せるため、入力と出力には合成データのみを使用し、結果ディレクトリへのアクセス権限を制限します。

実習2: 自身のHTTPゲートウェイのみをターゲットとして接続する

次のステップは、ローカルのガードレールゲートウェイをGarakのRESTジェネレーターに接続することです。RESTジェネレーターの正確な設定キーは、インストールされているGarakバージョンの公式リファレンスで確認してください。

plugins:
  generators:
    rest:
      RestGenerator:
        uri: http://host.containers.internal:8080/chat
        method: post
        headers:
          Content-Type: application/json
        req_template_json_object:
          message: "$INPUT"
          tenant_id: "redteam-test"
        response_json: true
        response_json_field: response
python -m garak 
  --target_type rest.RestGenerator 
  --config garak-rest.yaml 
  --probes promptinject

上記の名前とオプションはバージョンによって異なる場合があります。まず、–plugin_infoとリファレンスを確認してください。スキャン範囲、最大生成数、同時実行数、タイムアウト、コスト制限を設定し、テストゲートウェイ以外のIPアドレスはネットワークポリシーでブロックします。

Garakの結果の読み方

GarakのFAILは、検出器が応答から目標とする失敗の兆候を発見したことを意味します。これは直ちに実際の脆弱性が確定したことを意味するものではありません。

  1. どのプローブと検出器の組み合わせであったかを確認します。
  2. ターゲットエラーや空の応答が誤って判定されていないか確認します。
  3. ユーザー出力だけでなく、RAG・ツールトレースも確認します。
  4. 同じ条件で再現されるか繰り返します。
  5. 最小限の合成テストケースに絞り込んだ後、人間が期待される動作を定義します。

検出器が単純な拒否文言を基準にしている場合、言語や表現の変化によって誤検知する可能性があります。ガードレールの構造化された決定とツール呼び出しの有無を合わせて検証するカスタム検出器または後処理ゲートが必要になる場合があります。

実習3: PyRITをインメモリで開始する

PyRITの公式ドキュメントでは、パッケージのインストールとinitialize_pyrit_asyncを使用したフレームワークの例が提供されています。隔離された実習では、まずインメモリメモリを使用して、ディスクに会話が残る範囲を減らします。

python3 -m venv .venv-pyrit
source .venv-pyrit/bin/activate
python -m pip install --upgrade pip
python -m pip install pyrit
python -c "import pyrit; print(pyrit.__version__)"
import asyncio
from pyrit.setup import IN_MEMORY, initialize_pyrit_async

async def main():
    await initialize_pyrit_async(memory_db_type=IN_MEMORY)
    print("PyRIT in-memory lab initialized")

asyncio.run(main())

IN_MEMORYはプロセスが終了すると便利に消滅しますが、画面出力や外部プロバイダーのログまで消去する機能ではありません。プロンプトと応答には合成データのみを使用してください。

実習4: 単一ターンからターゲットを検証する

PyRITのターゲットは、攻撃対象となるAIシステムインターフェースです。公式ドキュメントの例では、OpenAIChatTargetとPromptSendingAttackを使用しています。この記事では、実際のキーをコードに直接記述せず、承認されたテストエンドポイント設定を環境から読み込むことを前提として、構造のみを示します。

import asyncio
from pyrit.executor.attack import PromptSendingAttack
from pyrit.output.attack_result.pretty import PrettyAttackResultMemoryPrinter
from pyrit.prompt_target import OpenAIChatTarget
from pyrit.setup import IN_MEMORY, initialize_pyrit_async

async def main():
    await initialize_pyrit_async(memory_db_type=IN_MEMORY)

    target = OpenAIChatTarget()
    attack = PromptSendingAttack(objective_target=target)

    result = await attack.execute_async(
        objective="합성 Test 문서의 접근 정책을 설명해줘"
    )

    printer = PrettyAttackResultMemoryPrinter()
    await printer.write_async(result)

asyncio.run(main())

この目的は、正常な接続を確認するスモークテストです。安全な単一ターン、スコアラーの検証、結果の保存範囲を確認した後でのみ、承認された複数ターン戦略に拡張します。

実習5: スコアラーと人間による判定の分離

PyRITスコアラーは、応答が目標を達成したかどうかをTrue・False、リッカート尺度、または分類で評価できます。LLMベースのスコアラーは柔軟ですが、それ自体のエラーとコストがかかります。

判定対象 優先方式
— —
ツール呼び出しの有無 構造化トレースの決定論的検査
テナント境界違反 文書ID・テナントIDの決定論的検査
秘密文字列の露出 合成カナリアの正確一致検査
拒否の意味・迂回成功 スコアラーと人間によるレビューを併用
回答品質・関連性 モデルスコアラーとサンプルレビュー

アタックモデルとスコアラーモデルをターゲットモデルから分離しても、両方とも間違っている可能性があります。スコアラーのバージョン、プロンプト、しきい値、実行環境を結果に記録し、未確定やエラーを成功として計算しないでください。

体系的なスキャンと適応型探索を併用する

Garak 넓은 Probe Scan
  ↓ 실패 후보
사람의 1차 분류
  ↓ 대화형 재현이 필요한 후보
PyRIT 단일·다중 Turn 실험
  ↓ 재현 가능한 최소 사례
Trace·권한·정책 검토
  ↓ 승인된 Finding
Promptfoo 회귀 Testcase + Guardrail 정책 변경

Garakで広範囲をスキャンし、PyRITで会話コンテキストを深く探索する流れは有用ですが、常にこの順序である必要はありません。重要なのは、両方の結果を同じfinding_id、ターゲットバージョン、ポリシーバンドル、トレースIDで関連付けることです。

Podmanサンドボックス運用例

podman network create --internal llm-redteam-lab

podman run --rm 
  --network llm-redteam-lab 
  --read-only 
  --cap-drop=all 
  --security-opt=no-new-privileges 
  --pids-limit=256 
  --memory=4g 
  --cpus=2 
  -v "$PWD/results:/results:Z" 
  localhost/llm-redteam-tools:VERSION

–internalネットワークでは外部APIを呼び出すことはできません。ローカルターゲットコンテナを同じネットワークに接続して完全にローカルで実習を行うか、外部プロバイダーがどうしても必要な場合は、許可された宛先のみを通過させる別のエグレスプロキシを設置します。ホストネットワーク、Dockerソケット、ホームディレクトリ、クラウド認証情報ディレクトリはマウントしないでください。

結果における個人情報とコストの保護

  • プロンプト・応答の原文は最小限の期間のみ保持します。
  • 実際の顧客対話の代わりに合成データセットを使用します。
  • JSONL・メモリDB・トレースのアクセス権限と暗号化を設定します。
  • APIキーと認証ヘッダーをログから削除します。
  • 最大ターン数、プローブ数、生成数、同時実行数、トークン数、コストを制限します。
  • ツールはモックまたは読み取り専用に置き換えます。
  • スキャン終了後、一時的なコンテナとシークレットを破棄します。

実習完了チェックリスト

  • 所有または明示的に許可されたテストターゲットのみを使用しました。
  • Garakのジェネレーター・プローブ・検出器・ハーネスの役割を区別しました。
  • PyRITのターゲット・アタック・スコアラー・メモリの役割を区別しました。
  • 全体スキャン前にテストターゲットでインストールを確認しました。
  • プローブファミリーと複数ターンの範囲を小さく開始しました。
  • 合成テナント、合成カナリア、モックツールを使用しました。
  • コンテナ権限、ネットワークエグレス、リソース制限を設けました。
  • FAIL・スコアを脆弱性の確定として自動解釈しませんでした。
  • ユーザー出力と内部ツール・RAGトレースを合わせて確認しました。
  • 承認された発見のみを最小限の回帰テストケースに昇格させました。

まとめ

GarakとPyRITは、既知の答えを再採点するツールではなく、現在のテストスイートの範囲外にある失敗候補を見つけるための探索ツールです。Garakはプローブと検出器で広範囲をスキャンし、PyRITはターゲット・アタック・スコアラー・メモリを組み合わせて会話型パスを深く調査します。

自動化が生成するのは判決ではなく、候補リストです。隔離されたテスト環境で実行し、人間がポリシー・権限・トレース・再現性を確認した後、価値のある発見のみをPromptfooテストケースとガードレールポリシーに昇格させるべきです。次回の最終回では、これらの発見を責任者・期待結果・ポリシーバージョンを含むテストケースに変換し、コントロールプレーンに安全にデプロイする全体のループを完成させます。

公式資料

※ Garakプラグイン名、PyRIT API、Python要件はバージョンによって異なる場合があります。コマンド実行前に、固定されたリリースの公式ドキュメントを確認し、許可されたサンドボックスで合成データを使用して検証してください。


Comments

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です