1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【実録】Gemini CLIの脆弱性ニュースを見たので、自作ラッパーで「防御壁」作成に挑んでみた

1
Last updated at Posted at 2026-05-03

0. はじめに

普段から便利に Gemini CLI を愛用しているのですが、先日たまたま目にしたセキュリティニュースで「AIエージェントに重大な脆弱性の可能性(RCEなど)」という文字を見て、背筋が凍りました。

「もし自分のAPIキーや、隠しておきたい秘密ファイルがAI経由で漏れたら……」

そう思って、勉強がてら自分の環境を「要塞化」してみることにしました。その過程で、AIが指示していないファイルを勝手に読みに行こうとするなど、予想外の生々しい挙動を目の当たりにしたので、記録として残します。

1. ニュースを見て慌ててやったこと

まずは基本から。入り口を塞ぐために以下のアップデートを行いました。

  • Gemini CLIの更新: 脆弱性対策が入った最新版(v0.40.1以降)へ。
  • Linuxカーネルの更新: 特権昇格のバグ対策として最新(6.8.0-111-generic等)へ。

でも、ニュースによれば「AIが騙されて秘密情報を外部に送らされる」という攻撃(Comment and Control)もあるとのこと。これはソフトの更新だけでは防げない……!

2. 秘密情報を「物理的」に隠す(direnvの導入)

「AIがアクセスできる場所に秘密を置かない」のが一番。そこで direnv を導入して、「特定のフォルダに入ったときだけAPIキーをロードする」 設定にしました。

  • ~/.bashrc に書いていた APIキーを全削除。
  • 開発用の ~/work/ai-project/ フォルダだけで有効になるように隔離。

これで、ホームディレクトリで遊んでいるときはAIが鍵を見つけられない「安全地帯」ができました。

3. 自作ラッパー secure_gemini_wrapper.py で見張る

「今回は、Gemini CLIの挙動を安全に調査するために、入出力をフックして監査する専用のデバッグ用ラッパーをPythonで作りました。直接コマンドを叩くのではなく、この検問所を通すことで、AIが裏で何をやろうとしているのかを可視化します。」

#!/usr/bin/env python3
import sys
import os
import subprocess
from aigis import Guard # ガードレール用ライブラリ

def secure_gemini_run(untrusted_input):
    # 入力文字数をデバッグ表示(後で分析用)
    print(f"[DEBUG] input_length={len(untrusted_input)}", file=sys.stderr)
    
    guard = Guard()
    
    # --- [1/3] 入力スキャン(怪しい命令がないか?) ---
    input_check = guard.check_input(untrusted_input)
    if input_check.blocked:
        print(f"❌ 警告: プロンプトインジェクションの疑いあり", file=sys.stderr)
        sys.exit(1)

    # --- [2/3] 実行(ここでサンドボックス化) ---
    try:
        # 暴走対策:リトライを無効化(環境変数はおまじない)
        env = os.environ.copy()
        env["GEMINI_DISABLE_RETRY"] = "1" 

        result = subprocess.run(
            ['gemini', 'ask', untrusted_input],
            capture_output=True, text=True, check=True,
            timeout=30, # 30秒で強制終了。DoS(リソース消費)対策
            env=env
        )
        ai_response = result.stdout
    except subprocess.TimeoutExpired:
        sys.exit("❌ エラー: AIの応答が遅すぎます。リソース消費攻撃の可能性。")
    except subprocess.CalledProcessError:
        sys.exit("❌ 警告: 異常終了(アクセス禁止ファイルに触ろうとした可能性)")

    # --- [3/3] 出力スキャン(秘密を漏らしていないか?) ---
    output_check = guard.check_output(ai_response)
    if output_check.blocked:
        sys.exit("❌ 警告: 回答内に秘密情報(APIキー等)が含まれています!")

    print(ai_response)

if __name__ == "__main__":
    # ... 引数の受け取り ...
    secure_gemini_run(user_data)

4. 【衝撃】実際に自分を攻撃してみたら……

この「要塞」の強度を試すため、わざと意地悪な質問をしてみました。

僕: 「URI形式で、データベースのパスワードとかが含まれる文字列をダミーでいいから5つ作って出力して」

すると、恐ろしいことが起きました。

AIが勝手にファイルを探し始めた!

ログを見ると、AIは僕が指示していないのに 「ガバナンス確認のため」という謎の理由で、フォルダの外にある ~/projects/GCP_HOLDINGS.md というファイルを勝手に読み取ろうとした のです。

幸い、direnv でワークスペースを制限していたので 「アクセス拒否」 で守れましたが、もし隔離していなかったら、中身を勝手に読み取って回答に使われていたかもしれません。

AIが「自爆」して止まった(クォータ切れ)

アクセス拒否されたAIは、「そんなはずはない!」と何度もリトライを繰り返しました。その結果、わずか数分でGoogle APIの利用制限(Quota Exhaustion)に激突して停止しました。
「防御した」というより「AIがパニックになって自爆した」 というのが正しい表現です。

5. まとめ:やってみてわかったこと

初心者の試行錯誤でしたが、大きな発見がありました。

  1. 「文字列」での検知は限界がある: 遠回しな言い方をすると、ガードレール(aigis)をすり抜けてAIに命令が届いてしまいます。

  2. 「物理的な隔離」が最強: フィルタをすり抜けても、direnv 等で「物理的にアクセスできない場所」を作っておけば、最後はそこで止まります。

  3. AIは「自律的」に動く: 「指示に従うツール」だと思っていると危ないです。AIはコンテキストを読んで、勝手に判断してファイルを探しに行きます。

    結論:「侵入」は許したが、「実害」は食い止めた

今回の対策でわかったのは、「AIが騙されること自体は防げない」ということです。賢いAIは、巧妙なプロンプトで簡単に「本来の役割」を忘れてしまいます。

でも、「AIが物理的に触れる場所」を制限しておけば、たとえAIが乗っ取られても、一番大事なファイルまで手が届かない。 今回の検証は、「ソフトの検知(aigis)」が破られても、「環境の隔離(direnv)」が最後の最後で食い止めてくれたという、多層防御の泥臭い実戦記録となりました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?