
自作の「AIアプリのセキュリティ設計を診断するツール」= Security Knowledge OS(SKOS) の使い方
この記事でやること
自作の「AIアプリのセキュリティ設計を診断するツール」= Security Knowledge OS(SKOS) の使い方を、実際に自分のAIエージェントへ適用しながら紹介します。
そして、そのために実装を確認していたところ、SKOSの守備範囲外にあった本物のバグ――任意コード実行につながるRCE(Remote Code Execution)の問題まで見つかった、という話です。
読み終えると、次のことが分かります。
* SKOSが何を診断するツールなのか
* YAML 1枚でどう使うのか
* FAIL / WARN / UNKNOWN が何を意味するのか
* 「AIの設計診断」と「コードレビュー」は別物だということ
* セキュリティツールにも明確な守備範囲が必要だということ
⸻
まずはデモ動画(81秒)
基本的な使い方から、自社ポリシーをルールとして追加するところまでを短くまとめています。
⸻
SKOSとは何か
ひとことで言うと、
AIアプリの構成をYAMLで書いて渡すと、「このAIの設計にはどんなセキュリティ上の注意点があるか」をルールベースで判定するツール
です。
実際に攻撃を仕掛ける脆弱性スキャナではありません。
AIシステムについて、
* 何を読むのか
* どんなツールを使えるのか
* 外部へ何を送れるのか
* Memoryを持つのか
* Credentialをどう扱うのか
* 人間の承認ポイントがあるのか
といった「設計情報」を入力し、その構造からリスクを確認します。
主な特徴は3つあります。
1. 既定ではLLMを使わない
通常の診断経路は決定論的なルールエンジンです。
そのため、同一バージョン・同一ルール・同一入力であれば、基本的に同じ判定になります。
既定の診断だけなら、外部LLMのAPI利用料も発生しません。
2. 分からないものをPASSにしない
SKOSでは、判定に必要な情報が不足している場合、
UNKNOWN
を正式な結果として返します。
つまり、
「情報が書いてないから、たぶん安全でしょう」
とは扱いません。
3. AIセキュリティの既存知見をルールへ落としている
OWASP、NIST、MITRE ATLASなどの知見を参考にしながら、AIシステムで起こり得る設計上のリスクをルールとして定義しています。
ただし、ここは重要です。
SKOSはOWASP/NIST/MITREへの網羅的な適合性評価ツールではありません。
記述された設計情報を、現在登録されているルールと照合して一次評価するPoCです。
また、判定の意味も限定されています。
FAIL
設計情報が、登録済みのリスク条件に該当したことを示します。
攻撃が実際に成功することを証明するものではありません。
UNKNOWN
判定に必要な情報が不足しているなど、現在の入力では判断できないことを示します。
⸻
使い方: YAML 1枚
診断したいAIアプリの構成を、決められた項目に沿ってYAMLへ書きます。
例えば、こんな構成です。
name: my-bot
system_prompt: "You summarize retrieved documents for the user."
rag:
enabled: true
sources:
- uploaded_documents
- web
tools:
- name: email_send
permissions: send
requires_approval: false
outbound:
enabled: true
destinations:
- smtp.example.com
credentials:
storage: env
exposed_to_model: "false"
このAIは、
* Webやアップロード文書を読む
* メール送信ツールを持つ
* 送信前の人間承認がない
* 外部通信が可能
* Credentialは環境変数に置く
という設計です。
実行します。
.venv/bin/skos assess my-bot.yaml
例えば、次のような結果になります。
overall_status: FAIL
[FAIL] TOOL-001
高影響ツールに人間の承認ゲートがない
[FAIL] PI-003
間接プロンプトインジェクションと外部送信の経路が存在する
[WARN] CRED-001
環境変数に生の認証情報を置く構成のため要確認
この結果を人間の言葉に直すと、
「外部の文書を読むAIが、人間の確認なしでメールを送れる」
という構造になっています。
もしWebページや文書の中に悪意ある指示が含まれていて、それをAIが命令として処理してしまった場合、外部送信までつながる可能性があります。
これが、いわゆる間接プロンプトインジェクションの危険な経路のひとつです。
なお、YAMLにはAPIキーやパスワードそのものを書きません。
例えば、
credentials:
storage: vault
のように、「どこへ保存されているか」という構成情報だけを書きます。
入力検査もありますが、SKOSの入力検査を「秘密情報を完全に検出してくれる仕組み」として頼るべきではありません。
⸻
項目は全部書かなくてもいい
SKOSの入力項目は、すべてを必須にはしていません。
分からない項目は省略できます。
ただし、判定に必要な情報が不足すると、
PASSではなくUNKNOWN
になります。
これは意図した挙動です。
セキュリティ評価では、
「情報がない」
と
「安全である」
は別だからです。
⸻
ここからが本題: 自分のAIに使ってみた
デモだけでは面白くないので、実際に自分が動かしているAIエージェントの構成もYAML化してみました。
そのAIは、
* ユーザーと会話する
* 会話内容などをMemoryへ保存する
* Web上の情報を取得する
* 外部情報をもとに話題を生成する
といった機能を持っています。
その構成をSKOSへ渡したところ、結果は FAIL になりました。
例えば、次のような判定です。
overall_status: FAIL
[FAIL] PI-003
間接プロンプトインジェクション+外部送信の経路
[WARN] MEM-001
永続Memoryが信頼できない外部コンテンツの影響を受ける構造
[UNKNOWN] GOV-001
承認ポリシーの情報不足により判定不能
中身を人間向けに言い換えると、
外部から取得した情報が、AIの行動や永続Memoryへ影響する可能性がある
ということです。
例えば外部の文章に悪意ある命令が仕込まれていて、それをAIが信用して処理した場合、
* Memoryへ不適切な情報を書き込む
* 後の会話へ影響を残す
* 外部送信処理へ影響する
といった設計上のリスクがあります。
もちろん、
「この構成なら必ず攻撃される」
という意味ではありません。
SKOSが示しているのは、
攻撃経路になり得る構造が存在している
ということです。
ここまでは、
「SKOSが想定どおり仕事をした」
という話でした。
問題は、この次です。
⸻
罠: SKOSの守備範囲の外に、もっと直接的なバグがあった
SKOSへ入力するYAMLを書くためには、当然ながら、
「このAIは実際にどんな処理をしているのか」
を確認する必要があります。
そこで実際のソースコードを読み直しました。
すると、
認証なしで任意コマンド実行につながり得る問題
を見つけました。
RCE、Remote Code Executionです。
問題のクラスとしては、
外部入力をシェルコマンドへ組み込む処理に、コマンドインジェクションへつながる可能性があった
というものです。
具体的な再現用ペイロードや攻撃手順は、この記事には載せません。
対象は自分のコードであり、すでに停止していたアプリでしたが、公開記事では脆弱性の原理と対策だけにとどめます。
⸻
なぜSKOSはRCEを見つけなかったのか
答えは単純です。
SKOSが見る対象ではないからです。
SKOSが見ているのは、
「AIが何を読み、何を記憶し、何を実行でき、どこへ送信できるか」
といった設計です。
一方で今回のRCEは、
HTTP APIやプロセス呼び出し部分の実装そのものに存在したコード上の問題
です。
つまり、レイヤーが違います。

この記事で一番言いたいのは、ここです。
「設計の診断」と「コードレビュー」は別のレイヤー。片方を通しても、もう片方の安全性は保証されない。
言い換えると、
SKOS PASS
≠
コードが安全
Code Review PASS
≠
AIの設計が安全
です。
今回、
SKOSはAIシステムの設計上のリスクを見つけました。
コードレビューはRCEにつながる実装上の問題を見つけました。
両方を見たから、両方が見えた。
⸻
RCE側の修正
実装上の問題については、主に次の修正を行いました。
1. シェルを経由しない実行方式へ変更
最も重要な修正です。
外部入力を含む文字列を、そのままシェルで解釈させる方式をやめました。
引数を明確に分離し、シェルのコマンド構文として解釈されない呼び出し方式へ変更しました。
2. 外部入力を許可形式で検証
入力値についても、
* 英数字
* ハイフン
* アンダースコア
など、用途上必要な文字だけを受け付けるよう制限しました。
ただし、これは補助的な防御です。
今回の根本対策は、
「危険な文字を頑張って消す」ことではなく、「そもそもシェルに解釈させない」こと
です。
3. 作業ファイルを専用の一時領域へ分離
一時ファイルや生成物についても、他の処理から分離された専用の一時ディレクトリを利用する形へ変更しました。
4. エラー応答から内部情報を除去
外部へ返すエラーメッセージについても、内部パスや実装詳細などの情報が不用意に漏れないよう一般化しました。
⸻
修正前の確認について
修正前には、
問題のある処理によって意図しないコマンド実行へ到達できること
を隔離した環境で確認しています。
対象は自分が管理するコードで、すでに停止していたアプリです。
第三者のシステムやサービスに対する検証ではありません。
そのうえで修正し、同じ経路から問題が再現しないことを確認しました。
⸻
一方、SKOSが出した設計リスクは残っている
RCEはコードのバグなので、コードを修正できます。
しかし、
外部コンテンツを読むAIが永続Memoryを持つ
という問題は、単純なプログラムミスではありません。
これはシステムの設計そのものに関係します。
例えば今後、
* 外部由来の情報へtrust levelを付ける
* 外部情報から直接Memoryを書き込ませない
* Memoryの書き込み経路と読み出し経路を分離する
* 永続Memoryへの保存前に別の検査を入れる
* 外部由来Memoryを後続処理で区別できるようにする
* 高影響アクションには人間承認を要求する
といった対策を検討する必要があります。
こちらは、次の開発フェーズの宿題として残しています。
⸻
ここで少し面白かったこと
SKOSを作った目的は、
AIシステムのセキュリティ設計をチェックすること
でした。
ところが実際には、
SKOSを試す
↓
AIの構成をYAMLにする
↓
構成を正確に書くためコードを読む
↓
SKOSが設計リスクを出す
↓
さらにコードを調べる
↓
RCEまで見つかる
という流れになりました。
SKOSそのものがRCEを検出したわけではありません。
でも、
設計を明示的に書き出す作業が、別レイヤーの問題まで見直すきっかけになった
という点は面白い結果でした。
セキュリティレビューは、
「このツールを通したから終わり」
ではなく、
システムを複数のレイヤーから見る作業
なのだと思います。
⸻
SKOSにも守備範囲がある
ここは強調しておきます。
SKOSは、
* Pentestツールではありません
* SASTではありません
* DASTではありません
* ソースコード脆弱性スキャナではありません
* セキュリティ保証を出す製品ではありません
現時点では、
AIシステムの設計情報を、登録されたルールに基づいて一次評価するPoC
です。
現在の評価結果も、controlled fixture上での挙動確認であり、実世界での網羅性や検出性能を証明するものではありません。
だからこそ、
「何を検出できるか」
だけでなく、
「何を検出しないのか」
も明示する必要があります。
⸻
まとめ
今回の話をまとめると、
* SKOSは、OWASP / NIST / MITRE ATLASなどを参考に定義したルールで、記述されたAIシステムの設計情報を決定論的に診断するツール
* 基本的な使い方はYAML 1枚+skos assess
* 情報不足は安全扱いせず、UNKNOWNとして返す
* 自分のAIへ使ったところ、間接プロンプトインジェクションやMemory周辺の設計リスクが出た
* YAMLを作るためにコードを確認したところ、SKOSの守備範囲外だったRCEにつながる問題まで見つかった
* RCEはコードレビュー側で修正した
* AIの設計リスクについては、別途設計側の対策が必要
* 設計診断とコードレビューは別レイヤーであり、片方だけではシステム全体の安全性は保証できない
という結果になりました。
自分で作ったセキュリティ診断ツールを自分のAIへ使ったら、
「お前のAI、ここ危ないぞ」
と言われ、
さらに調べたら、
「いや、それとは別にコードも危ないぞ」
まで出てきました。
セキュリティ、層が厚い。
⸻
Security Knowledge OS
GitHub:
デモ動画:
⸻
#AIセキュリティ #AIエージェント #サイバーセキュリティ #RCE #プロンプトインジェクション #OSS #個人開発 #コードレビュー #AIガバナンス #SKOS