LLM×TDDに潜む落とし穴。テストの制約がセキュリティリスクを招く事例
公開日
セキュリティ
近年、大規模言語モデル(LLM)をソフトウェア開発に導入する動きが活発になっています。LLMは極めて迅速にコードを生成できる一方で、出力されたコードにセキュリティ上の脆弱性や、保守性を低下させる「コードスメル(不吉な臭い)」が含まれる問題が指摘されています。
本記事では、スウェーデンのブリーキンゲ工科大学の研究チームが発表した論文「Assessing TDD as a safeguard for LLM」に基づき、その検証結果を整理して紹介します。
LLM開発におけるTDD検証実験の概要
本研究では、LLMによるコード生成時に「テストファースト」アプローチを適用することで、セキュリティ脆弱性やコードスメルを減らせるかを確かめるために、比較実験が行われました。
調査の対象として、実験は同大学のコンピュータサイエンス専攻の学生およびプロの開発者1名を含む計10名を対象に実施されています。
実験の主な条件は以下の通りです。
- 参加者のグループ分け:
- SPG(標準プロンプティンググループ): 通常のプロンプトでLLMに指示を出す5名。
- MTG(修正TDDグループ): テストケースを作成した上でLLMに最小限の実装コードを生成させ、リファクタリングを繰り返す5名。
- 使用したLLM: Anthropicの「Claude Opus 4.6」(ログ記録用の専用プロキシ経由でアクセス)。
- 開発課題: Javaおよび軽量Webフレームワーク「Javalin」を用いた、認証やアクセス制御を含むWebアプリの拡張。制限時間は2.5時間。
セキュリティ脆弱性の比較結果:TDDは守りとして機能したか
実験で作成されたコードのセキュリティ検証は、OWASP ZAPを用いた動的スキャン、手動の侵入テスト、およびOWASP ASVS基準に基づくレビューを組み合わせて行われました。
分析の結果、TDDを用いたグループ(MTG)と、通常のプロンプトを用いたグループ(SPG)の間で、検出されたセキュリティ脆弱性の全体数に統計的な有意差は見られませんでした。
以下の図表1は、両グループで検出された脆弱性の深刻度別の発生数です。
| 深刻度 (Severity) | TDDグループ (MTG) | 標準プロンプティング (SPG) |
|---|---|---|
| Critical(緊急) | 2 | 1 |
| High(高) | 6 | 5 |
| Medium(中) | 15 | 15 |
| Low(低) | 0 | 2 |
| None(なし) | 0 | 2 |
| 合計 (Total) | 23 | 25 |
図表1:検出された脆弱性のグループ別比較
統計解析(マン・ホイットニーのU検定)におけるp値は0.6015であり、脆弱性の発生傾向に明確な違いは確認されませんでした。TDDアプローチを採用しても、セキュリティ面での直接的な保護効果は得られなかったことを示しています。
コードスメル密度から見る構造的品質の検証
次に、コードの保守性や構造的欠陥を示す「コードスメル」について、SonarQubeを用いた静的分析による検証結果を確認します。
各参加者が解決したタスク(ユーザーストーリー)の数が異なるため、本研究では「総コードスメル数」を「解決したタスク数」で割った「コードスメル密度(CSD)」を指標として採用し、評価を行いました。
以下の図表2は、各参加者のコードスメル数と解決したタスク数の一覧です。
| 参加者ID | グループ | 総コードスメル数 (TCS) | テストカバー率 | コードスメル密度 (CSD) | 完了したタスク数 (TUS) |
|---|---|---|---|---|---|
| TU1 | TDD (MTG) | 26 | 58.7% | 3.3 | 8 |
| TU2 | TDD (MTG) | 17 | 59.3% | 3.4 | 5 |
| TU3 | TDD (MTG) | 9 | 22.7% | 1.3 | 6 |
| TU4 | TDD (MTG) | 23 | 74.6% | 3.8 | 6 |
| TU5 | TDD (MTG) | 12 | 52.6% | 1.3 | 9 |
| SU1 | 標準 (SPG) | 46 | 32.6% | 2.2 | 21 |
| SU2 | 標準 (SPG) | 12 | 50.6% | 1.7 | 7 |
| SU3 | 標準 (SPG) | 33 | 72.9% | 2.2 | 15 |
| SU4 | 標準 (SPG) | 32 | 0.0% | 2.7 | 12 |
| SU5 | 標準 (SPG) | 14 | 56.2% | 1.4 | 10 |
図表2:参加者別のコードスメルおよび解決タスク数の一覧
分析の結果、TDDグループの平均CSDは2.62、標準グループの平均CSDは2.04となりました。統計的な有意差(p値 = 0.601508)は認められず、TDDを導入してもコード品質が向上する結果にはなりませんでした。
また、解決したタスク数に注目すると、標準グループが平均13件であったのに対し、TDDグループは平均6.8件にとどまりました。これは、テスト作成の手間やリファクタリング作業による手順の増加が影響していると考えられます。
開発者の経験やプロンプトの質が及ぼす影響
研究では、結果を左右する要因を整理するために、参加者の「プロンプトスキルの質」や「事前のプログラミング・TDD経験値」を考慮した分析も行われました。
- プロンプト品質の影響: プロンプトの品質が高かった群(HPQ)と低かった群(LPQ)を比較しましたが、脆弱性数やコードスメル密度において明確な差は見られませんでした。
- 共分散分析(ANCOVA)による傾向: 分析を進めると興味深い傾向が確認されました。標準グループ(SPG)ではプロンプトの質が高まるほど成果物の品質が向上した一方、TDDグループ(MTG)ではプロンプトの質が向上しても、出力されるコードスメル密度が高くなる傾向が見られました。
これらの分析から、単にプロンプトの書き方を工夫するだけでは、TDDを組み合わせたLLM開発におけるセキュリティや品質の問題を簡単には解決できないことが分かります。
TDDがLLMのデフォルトセキュリティを阻害する罠
本研究において特に注意すべき結果として、「ハッシュ化されていないプレーンテキストの状態でパスワードが保存される不具合」が、TDDを適用したグループ(MTG)でのみ2件発生した点が挙げられます。標準プロンプティングのグループでは、この不具合は発生しませんでした。
プロンプトの履歴を確認したところ、多くの参加者はパスワードのハッシュ化についてLLMに直接指示を出していませんでした。それにもかかわらず、なぜTDDグループのみが安全ではないコードを出力したのでしょうか。
研究チームは以下のように考えています。
TDDの最初のフェーズ(Red)において、開発者が記述したテストケース(例えば「特定の文字列がデータベースに正しく格納されるか」を確認するシンプルな検証など)が、LLMの解決策の範囲を狭めてしまった。その結果、LLMが本来備えている「パスワードはハッシュ化して安全に保存する」という初期設定の配慮が働かなくなり、テストをパスするための最も単純な方法(プレーンテキストでの保存)が選択された。
これは、安全性を確認するために書いたテストケースが、場合によってはLLMの柔軟な判断を奪い、標準的なセキュリティ機能をオフにしてしまう盲点になり得ることを表しています。
まとめ
本研究の結果は、人間の手による開発で有効とされてきたTDDという手法が、LLMを介したワークフローにおいてそのまま同じ効果を発揮するわけではないという事実を物語っています。
日々の開発業務に活かせる教訓として、以下の2点を整理できます。
- 自動テストだけでセキュリティ対策を済ませない: TDDによるテストが存在していても、LLMが安全なコードを出力する保証にはなりません。コード生成後はこれまで通り、コードレビューや静的・動的解析ツールによるチェックが欠かせません。
- テスト記述によるLLMの視野狭窄を考慮する: LLMに対してテストのみを提示して実装を行わせる場合、LLMが目の前のテストをパスすることを最優先し、例外処理や暗黙のセキュリティ要件を省いてしまうケースがあります。指示を出す際は、何が求められているかを明確に定義する必要があります。
今後は、テストそのものにセキュリティの検証要件をあらかじめ組み込むアプローチや、他のモデルにおける挙動の違いについて、さらなる検証が待たれます。
Webサービスや社内のセキュリティにお困りですか? 弊社のサービス は、開発チームが抱える課題を解決し、生産性と幸福度を向上させるための様々なソリューションを提供しています。ぜひお気軽にご相談ください!
参考資料: