こんにちは!PSIRT red team の kaworu と yusui です。 最近力を入れて取り組んでいる、 AIエージェントを利用した脆弱性診断の取り組みについて紹介します。
取り組みの背景
はじめに、現在のfreeeの脆弱性診断の体制と、取り組みの背景についてです。
freeeの脆弱性診断の流れとしては、開発チームから、設計レビューの依頼をきっかけに始まります。 セキュリティ観点でレビューを行い、あわせて脆弱性診断が必要な対象を決定しています。診断が必要なものは準備、診断作業、そして結果が開発チームに共有、修正が必要なものは対応を依頼しています。
上述のような流れなのは、Webアプリケーションの脆弱性診断はソースコードに変更の入ったタイミング、つまりリリースごとの実施を理想として体制を作ってきたためです*1。 その結果、以下のような課題をずっと抱えています。
- リリースごとの小さな単位で診断対象を決めているため、外部のセキュリティ企業に依頼するにも、提供されているサービスの最小の依頼数の小さな単位の依頼になること。
- 複数まとめての依頼するにも、社内のリリーススケジュールが流動的であり調整コストが非常に高いこと。
- 診断の内製化にて様々な改善や自動化、診断担当の熟練度によるスピードアップで対応してきたものの、依頼量の増加も引き続き見込まれ、このままだと量に負けてしまうこと。

そして、以前から色々と話題だったAIとソフトウェア開発。 2025年の年明けごろからは、さらにAIエージェントが存在感を示し、毎日目まぐるしいですね。
従来の脆弱性診断のスタイルで量に負ける前に、こちらもAIエージェントで迎える準備をしていきましょう……!
脆弱性診断 with AI エージェント、はじめました。
現在の脆弱性診断 with AIエージェントの構成
現時点ではAIエージェントとしてClineを利用し、ソースコードベースでの脆弱性診断を行っています。

この記事では、特に脆弱性診断 with AIエージェントでポイントになる、 Guardrailと Memory Bankについて紹介します。
Guardrail
AI エージェントはOSコマンドの実行をすることができます。 もちろん、ユーザの承認を得る必要がありますが、よく分からずに危険なコマンドを実行してしまったり、auto-approveして欲しくありません。
また、freeeでは、LLMにInputとして渡してもいい情報をセキュリティレベルとして定義しています。 違反するような情報をLLMのInputとして渡さないよう、自動的にBlockする仕組みも必要です。
こういった懸念に対応するために、Guardrailを設定しています。
当初、 freee独自の情報レベルの取り扱いに準じるように、プロンプトのInput/Outputに対してAWS BedrockのGuardrailsを適用する方法で検証していました。 しかし、どうしてもQuotaに引っかかってしまうため、現在は "独自Guardrail"を運用しています。 社内独自で開発されているLLM基盤を経由して通信させ、その基盤側で自動チェックを行うことで、AIエージェントで扱って良いセキュリティレベルとなるように担保しています。
Memory Bank
これまでの脆弱性診断では、診断担当が動的なテストに加えて、ソースコードや設計資料なども確認しています。 私たちが培ったプロダクトごとのアーキテクチャや依存関係、コードを追うときのコツなどを保存することで、AIエージェントに仕事をしてもらうときに参照してもらい、より良い結果を期待するものです。
Memory Bank の仕組み自体は、所謂プロンプトを工夫することでLLM自身にナレッジをファイルに出力させ、別のTask起動時にまずナレッジを読み込んでから作業を開始させるようにするものです。 Memory Bank のプロンプト自体は公式でも公開されていますが、これは開発向けになっている印象でしたので、独自に脆弱性診断のためにカスタマイズしたMemory Bank構成を設計して使用しています。
優秀な新人さんが毎回来るようなものなので、脆弱性を見つけるために必要な情報を保管して、Task開始時にMemory Bank からナレッジを読み出してもらっています。
取り組み始めての所感
まずは気になる精度について。 最初は、診断担当による従来の手法で行ったもの、AIエージェントによる脆弱性診断のみ実施したもの、両方を比較しながら実施しました。 いわゆるREST APIのプロダクト、特にコードから確認できるものについては、十分な結果を得ています。
コード全体のプロダクトの仕様を考慮したビジネスロジックなどは、まだ苦手そうなところでした。 これらについては、Memory Bankを充実させていったり、QAと連携し、別のアプローチで担保するなどの方法が取っていこうと考えています。
それから、診断の所要時間について。 現時点ではAIエージェントでの診断を実施し、結果は診断担当がレビューしています。 不足する部分は追加の指示であったり、診断担当が従来手法で診断を行った結果を渡し、再度AIエージェントの診断を走らせています。
おおよその感覚ですが、従来の脆弱性診断で、1営業日(8時間)の規模感の診断は、2時間もあれば完了できるかな、というところです。 また、この2時間のうちほとんどは、前述のように診断結果の精査に利用したり、不足があれば動的な診断を行うのに要する時間であり、AIエージェントの出力自体は2,3分です。 Memory Bankの内容や、与える指示の的確さによって、まだまだ結果にばらつきがあるので、診断ごとにMemory Bankを更新しながら進めています。
次の理想として
量の問題もありますが、リリース単位での脆弱性診断の実施は、どうしても脆弱性診断という営みがリリースのブロッカーになります。 これまでも、診断がブロッカーにならないような試行錯誤を行ってきました。 スピードアップはできても、まだまだリリース単位の脆弱性診断自体は外せない、という状況でした。 次の理想として、開発のタイミングでAIエージェントによる脆弱性診断を実施、結果に問題なければそのままリリース つまり、従来の脆弱性診断のリリースブロックをなくす方向に持っていきたいと考えています。 そのためにAIエージェントによる脆弱性診断だけで十分に精度が出るようになっている必要があります。
おわりに
これまで新たな取り組みについて紹介してきました。本格的にAIエージェントによる脆弱性診断を取り組み始めたのはここ3ヶ月になるのですが、 この取り組みに手応えを感じているのは、これまでの脆弱性診断の蓄積があるからこそとも考えています。 過去にセキュリティの専門家へ依頼した診断のレポートや、内製での診断の日々の記録、freeeではここを重点的に見た方が良い、こう追いかけるのが良い、ときには、開発チームとのやりとりなど、たくさんの蓄積があってこそだと考えています。
4月からは、次の理想に向けて進めていきます!
