11月5日、InfoWorldが「Your LLM writes good SQL. That's not the same as safe SQL」と題した記事を公開した。LLMが生成するSQLの「正確さ」と「安全さ」は別問題であり、アクセス制御をモデルではなくコードで担保すべきだという実践的な知見を紹介している。製薬業界の実案件で発覚した「正しく動くが、見せてはいけないデータを返す」クエリの問題を起点に、設計上の落とし穴と対策を具体的に解説する内容だ。
「正しいSQL」が「正しい答え」とは限らない
LLMによるText-to-SQL(自然言語からSQLを生成する技術)の評価は、多くの場合こうだ。質問を投げ、クエリが動いて結果が期待通りなら合格。しかしこのテストが見落とすのは「誰が聞いたか」という文脈だ。
記事の筆者は、製薬業界の営業・フィールドパフォーマンスデータを扱う分析ツールをSnowflake Cortex上で構築した経験を持つ。そのツールは確かに機能した。ユーザーが英語で質問すれば、数日かかっていた分析が数分で返ってくる。だが、あるユーザーが「自分の担当病院の四半期売上を見せて」と入力したとき、そのリージョン全病院のデータが返ってきた。SQLは文法的に正しく、クエリも動いた。問題は結果そのものだった。
これはマルチテナントのSaaSアプリ、HRシステム、財務ツールでも同様に起こりうる。
プロンプトはアクセス制御ではない
よくやりがちなのが、システムプロンプトに「自分のテリトリーのデータのみ表示すること」と書いて終わりにするアプローチだ。しかしプロンプトはあくまで「示唆」にすぎない。モデルはそれを無視したり、複雑な質問の中で忘れたり、誤読したりする。
筆者が推奨するのは、生成されたSQLをパースして実行前に書き換えるというアプローチだ。ルールをモデルが回避できないコードの層に置く。900件のテストクエリを使ったベンチマーク(元記事が参照する論文「Governed LLM-to-SQL for Pharma Commercial Data」の合成データによる検証)で確認された最も多い修正内容は以下の通りだ:
WHERE句への行フィルター追加: 285件- カラムマスキング: 240件
- スコープ制限: 165件
「許可か拒否か」の二択では足りない
同じ900クエリのうち、40%はそのまま実行可能だった。だが残り60%には何らかの介入が必要だった:
- 行フィルターが必要: 20%
- カラムマスキングが必要: 15%
- JOINの書き直しが必要: 11.7%
- 人間のレビューに回した: 6.7%
- 完全にブロック: 6.7%
大半のユーザーはそれでも有用な答えを得られた。ただし「より安全な形で」だ。単純なブロック・許可の二択ではなく、クエリを変形して安全な範囲で応答するという中間的な対応が、実用上は最も多く求められるケースだということが数字からも読み取れる。
実装上のチェックポイント
筆者が挙げる具体的な対策は次の通りだ:
- モデルに渡す情報を絞る: クエリを生成する前に、質問者のロール・部署・担当テリトリー・アカウントを参照し、その人が使えるテーブルとカラムのみをモデルに提示する。機密フィールド(顧客ID、契約条件、給与など)はメタデータカタログでタグ付けし、最初から候補に出さない。
- 実行前バリデーション:
SELECT *、スコープをまたぐ取得、過大な結果セット、危険なJOINはクエリ実行前に弾く。 - 権限の狭いDBアカウントをゲートウェイ経由で使う: プロンプトインジェクション(悪意ある入力でモデルを誘導する攻撃手法)や誤生成が起きても、DBレベルの権限が壁になる。
精度の数字が隠す「漏洩」問題
精度指標だけを見ていると見落とすのが、不正アクセスによるデータ漏洩数だ。検証では:
- 素のText-to-SQL: 一部クエリで最大約80件の無権限行を返した
- 静的なロールベースアクセス制御(RBAC): コンテキストを考慮できないため依然として漏洩が発生
- ポリシー対応アプローチ: 漏洩ゼロ、かつ1クエリあたりの追加レイテンシは約6.5ミリ秒
ユーザーは気づかない。だがコンプライアンスチームが「誰が何を見たか」を問いに来たとき、ログがなければ数週間かかる調査が始まる。質問・ユーザーコンテキスト・適用ポリシー・最終SQL・結果のセットを記録しておくことが必要だ。LLMを使った分析基盤では、モデルの精度と同等かそれ以上に、監査可能性の設計が重要になる。
優先順位は「誰が使うか」を先に決めること
筆者の結論はシンプルだ。「モデルがどれだけ賢いか」を考える前に、「このユーザーは誰か」を先に決めること。アクセスルールを正しく設計してから、精度をチューニングする順番が正しい。モデルはSQL生成の精度を上げ続けるが、信頼できるシステムを作るのは、クエリの実行前後にある仕組みだ。
詳細はYour LLM writes good SQL. That's not the same as safe SQLを参照していただきたい。




