3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

macOS のキーチェーンで ~/.zshrc に平文で書いた認証情報を撲滅しよう

3
Posted at

はじめに

本記事では、~/.zshrc に直書きしたトークンや API キーを macOS のキーチェーンに移し、シェルの起動時に取り出す方法を紹介します。

要点は、次の1行の置き換えです。.zshrc には値を書かず、キーチェーンから値を取り出すコマンドを書きます。

~/.zshrc
- export OPENAI_API_KEY='sk-proj-abc123...'
+ export OPENAI_API_KEY="$(security find-generic-password -a "$USER" -s zshrc-OPENAI_API_KEY -w)"

背景:.zshrc の直書きは、AI エージェントの作業で漏えいする

API キーを .zshrc に export で書いておく方法は、昔から広く使われています。

~/.zshrc
export OPENAI_API_KEY='sk-proj-abc123...'
export GEMINI_API_KEY='AIzaSy...'

Claude Code などの AI エージェントは、頼まれた作業とは別に、環境を調べるために .zshrc を読むことがあります。利用者が値を見せるつもりでなくても、次のような場面で、値がツールの実行結果に含まれます。

  • 利用者が PATH やシェルの設定を直すよう頼むと、AI エージェントは .zshrc 全体を読みます。
  • AI エージェントは、特定の行を直すときに、確認のため前後の行も読みます。トークンの行が近くにあれば、その行も一緒に読まれます。
  • AI エージェントは、設定の場所を探すために、ホームディレクトリのドットファイルを grep します。一致した行は、値ごと出力されます。
  • 利用者が Mac の移行やドットファイルの整理を頼むと、AI エージェントは .zshrc の中身を一通り読みます。

たとえば、AI エージェントが PATH の設定を確かめるために次のコマンドを実行すると、すぐ下の行にあるトークンも出力されます。

AI エージェントが実行したコマンドと、その出力
$ sed -n '55,60p' ~/.zshrc
# Created by `pipx`
export PATH="$PATH:$HOME/.local/bin"

# ChatGPT - openai
export OPENAI_API_KEY='sk-proj-abc123...'

問題は、値が画面に表示されることではありません。ツールの実行結果がコンテキスト(モデルへの入力)に入ることです。実行結果がコンテキストに入った時点で、次の2つが起きます。

  1. 値がサービスの提供元に送信されます。 AI エージェントは、ツールの実行結果を次のリクエストに含めてモデルに送ります。Claude Code を Anthropic の API で使う場合、送信先は Anthropic です。端末で省略表示されていても、実行結果はモデルに送られます。
  2. 値がローカルの会話の記録に残ります。 Claude Code は、会話の記録を ~/.claude/projects/<作業ディレクトリ>/<セッションID>.jsonl に保存します。ツールの実行結果も、そのままの形で保存されます。記録は既定で30日間残ります(cleanupPeriodDays で変えられます)。
~/.claude/projects/.../<セッションID>.jsonl(1行を抜き出して整形したもの)
{
  "type": "user",
  "message": {
    "role": "user",
    "content": [
      {
        "type": "tool_result",
        "tool_use_id": "toolu_01...",
        "content": "# ChatGPT - openai\nexport OPENAI_API_KEY='sk-proj-abc123...'\n"
      }
    ]
  }
}

人間が作業するときは、値の書かれた行を読み飛ばせました。AI エージェントは、ファイルを読んだ時点で値をコンテキストに入れてしまいます。一度送信した値は、あとから取り消せません。

.zshrc や .env に平文で書いた値は、以前から、リポジトリへの誤った commit などで漏えいすることがありました。AI エージェントを使うようになって、漏えいの経路がさらに増えています。

対策:キーチェーンに保存し、シェルの起動時に取り出す

macOS には、パスワードや鍵を暗号化して保存するキーチェーンがあります。security コマンドを使うと、ターミナルからキーチェーンに値を保存したり、取り出したりできます。

保存する

security add-generic-password で、値をキーチェーンに保存します。-w を最後に置き、値を書かずに実行すると、security が対話型(インタラクティブ)で値の入力を求めるので、そこに値を貼り付けます。

ターミナル
$ security add-generic-password -U -a "$USER" -s zshrc-OPENAI_API_KEY -w
password data for new item:          ← 値を貼り付ける(画面には表示されません)
retype password for new item:        ← もう一度貼り付ける

各オプションの意味は次のとおりです。

オプション 意味
-a "$USER" アカウント名。自分のユーザー名にします。
-s zshrc-OPENAI_API_KEY サービス名。取り出すときに、この名前で項目を探します。
-w 値。最後に置いて値を書かないと、対話型で値を入力できます。
-U 同じ項目が既にあれば、上書きします。

-w sk-proj-abc123... のように値をコマンドに直接書くと、実行中は ps の出力に、実行後は ~/.zsh_history に、値が平文で残ります。

サービス名は zshrc-<変数名> にそろえておくと便利です。「キーチェーンアクセス」で「zshrc-」と検索すると、保存した項目を一覧できます。

キーチェーンから取り出す

.zshrc の export の行を、キーチェーンから値を取り出すコマンドに置き換えます。

~/.zshrc
- export OPENAI_API_KEY='sk-proj-abc123...'
+ export OPENAI_API_KEY="$(security find-generic-password -a "$USER" -s zshrc-OPENAI_API_KEY -w)"

security find-generic-password に -w を付けると、値だけを出力します。シェルは起動するたびにこのコマンドを実行し、出力された値を環境変数に入れます。

確かめる

新しいタブを開き、値の先頭の数文字と文字数だけを表示して、値が入っていることを確かめます。先頭の sk- は、キーの種類を表す固定の文字列です。表示しても、値の推測にはつながりません。

ターミナル
$ echo "${OPENAI_API_KEY[1,4]}... (${#OPENAI_API_KEY} 文字)"
sk-p... (51 文字)

この方法で防げること、防げないこと

キーチェーンが守るのは、ファイルに書かれた値です。シェルが起動して環境変数に入った値までは守れません。

漏えいの経路 防げるか
AI エージェントが .zshrc を読む。利用者が .zshrc を表示する、共有する 防げます
利用者が .zshrc を dotfiles リポジトリに commit する 防げます
シェルの起動後に、環境変数を表示する(例:AI エージェントが調査のために env | grep -i api を実行する) 防げません
同じユーザーで動くプログラムが、security で値を取り出す 防げません

最後の行について補足します。security コマンドで保存した項目は、security コマンドからなら確認のダイアログなしで取り出せます。キーチェーンのロックが解除されている間は、同じユーザーで動くスクリプトも、同じ方法で値を取り出せます。

また、キーチェーンがロックされている環境では、security が値を取り出せず、環境変数が空になります。SSH でログインしたシェルや、cron から実行するジョブが該当します。

キーチェーンに移しても、すでに漏えいした値は無効になりません。AI エージェントに .zshrc を読ませたことがあるなら、その値は作り直してください。

おわりに

AI エージェントが利用者の環境のファイルを読むようになり、.zshrc に直書きした値は、以前より漏えいしやすくなりました。今回紹介した方法をはじめ、平文の認証情報を撲滅する手法は様々あります。少しでも安全に開発できるよう対策していきましょう。

3
0
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
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?