1
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?

APIキーを export するとシェル履歴に平文で残る:先頭スペースが効く条件と history -d -2 で消す方法(bashで確認)

1
Posted at

結論

  • export OPENAI_API_KEY=sk-... のようにキーをコマンドに直接書くと、bash はその行を ~/.bash_history に平文で保存します。curl -H "Authorization: Bearer ..." も同じでした(筆者の環境で確認)。AIエージェントがファイルを読める場所なら、履歴ファイルも読める場所です。
  • 行の先頭にスペースを入れると残らないのは、HISTCONTROL に ignorespace(または ignoreboth)が入っているときだけです。設定がないシェルでは、スペースで始まる行もそのまま残りました(bash公式・筆者の環境)。
  • 打ってしまった直後なら history -d -2 で消せます。-1 は history -d 自体を指すので、history -d -1 ではキーの行は消えませんでした。キーは read -rs で入力すると履歴に残りません(筆者の環境で確認)。

この記事は「AIエージェントと秘密情報」の検証シリーズです。新しい検証は X(@supportapp3_lab)でもお知らせしています。

AIエージェントのCLIを試すとき、「とりあえず export でAPIキーを入れる」ことがよくあります。.env を読ませない設定をしていても、同じキーがシェルの履歴ファイルに平文で残っていれば意味が薄れます。どの打ち方で残り、どうすれば残らないかを bash で確かめました。

検証環境と範囲

  • Debian 13.7 / GNU bash 5.2.37
  • 一時ディレクトリを HOME にし、HISTFILE を指定した対話シェル(bash --norc -i)にコマンドを流し込み、終了後に履歴ファイルの中身を見ました。
  • キーはすべてダミーの文字列です。zsh・fish は試していません。

1. export で直接書いたキーは、そのまま残る

export DEMO_API_KEY=sk-dummy-AAAA1111

終了後の履歴ファイル:

export DEMO_API_KEY=sk-dummy-AAAA1111
echo done
exit
打ち方 履歴ファイルに残ったか
export DEMO_API_KEY=sk-dummy-... 残った
curl -H "Authorization: Bearer sk-dummy-..." ... 残った
先頭スペース+HISTCONTROL=ignorespace 残らない
先頭スペース+HISTCONTROL なし 残った(先頭のスペースごと)
read -rs DEMO_API_KEY で入力 残らない(read -rs DEMO_API_KEY という行だけ残る)
bash -c '...' の非対話シェル 履歴ファイル自体が作られない

最後の行のとおり、AIエージェントが bash -c のような形で実行したコマンドは、この検証では履歴ファイルに入りませんでした。ただしエージェントによっては、実行したコマンドを自分の会話記録に保存します(Claude Code の例はこちらの記事)。

2. 先頭スペースが効くのは設定があるときだけ

bash 公式マニュアルでは、HISTCONTROL に ignorespace が含まれるとき、スペースで始まる行を履歴に保存しない、と説明されています。ignoreboth は ignorespace と ignoredups をまとめた指定です(Bash Variables)。

Debian の /etc/skel/.bashrc には HISTCONTROL=ignoreboth が書かれていました。これは新しいユーザーの .bashrc のひな形ですが、.bashrc を読まないシェルや、別の内容の .bashrc を使う環境では効きません。自分のシェルで効いているかは、次で確かめられます。

echo "$HISTCONTROL"

ignorespace か ignoreboth が出なければ、先頭スペースでは防げません。

3. 打ってしまったら、終了前に history -d -2

bash は、シェルを終了するときに履歴を $HISTFILE に書き出します(Bash History Facilities)。実際、シェルの実行中は履歴ファイルにキーの行はなく、終了後に入りました。

そのため、打った直後なら履歴の一覧から消せば、ファイルには書かれません。

export DEMO_API_KEY=sk-dummy-GGGG7777
history -d -2

終了後の履歴ファイルは history -d -2 と exit の2行だけでした。

history -d -1 では消えませんでした。マニュアルでは負の数は末尾から数え、-1 は今打った history -d 自体を指します(Bash History Builtins)。

すでにファイルに書かれてしまった場合は、すべての端末を閉じてから履歴ファイルを編集します。開いたままのシェルがあると、終了するときにそのシェルの履歴でファイルが書き直されます(マニュアルの「終了時に書き出す」動きから考えた推測で、複数端末の組み合わせは試していません)。漏れた可能性があるキーは再発行するのが確実です。

4. そもそも打たない:read -rs

キーを画面にも履歴にも出さずに環境変数へ入れるには、read を使います。

read -rs OPENAI_API_KEY   # 入力しても表示されない
export OPENAI_API_KEY

履歴に残るのは read -rs OPENAI_API_KEY と export OPENAI_API_KEY の行だけで、キーの値は残りませんでした。

5. AIエージェントに履歴ファイルを読ませない

Claude Code では、Read の deny ルールにホームからのパス(~/)を書けます(Configure permissions)。

~/.claude/settings.json
{
  "permissions": {
    "deny": [
      "Read(~/.bash_history)",
      "Read(~/.zsh_history)"
    ]
  }
}

公式によると、Read の deny は Claude の組み込みのファイルツールと、Bash で cat などファイル名を指定するコマンドには効きますが、Python スクリプトのように中でファイルを開く処理には効きません。確実に止めるにはサンドボックスを使うよう案内されています。.env の deny の書き方はこちらの記事にまとめています。

6. 履歴に残っていないか確かめるスクリプト

値は表示せず、ファイル名と行番号だけを出します。キーらしい文字列の判定は目安で、見落としも誤検知もあります。

check_history.sh
#!/usr/bin/env bash
# シェル履歴に秘密らしい文字列が残っていないかを調べる(値は表示しない)
for f in "$HOME/.bash_history" "$HOME/.zsh_history" "$HOME/.local/share/fish/fish_history" "$HOME/.python_history" "$HOME/.psql_history" "$HOME/.mysql_history"; do
  [ -f "$f" ] || continue
  grep -nE '(API_KEY|TOKEN|SECRET|PASSWORD|PASSWD)[A-Z_]*=|Authorization: *Bearer|sk-[A-Za-z0-9_-]{8,}|ghp_[A-Za-z0-9]{20,}|github_pat_|AKIA[0-9A-Z]{16}|xox[bp]-' "$f" \
    | cut -d: -f1 | sed "s|^|$f: 行 |"
done
echo "確認おわり(何も出なければ該当なし)"

ダミーの履歴で試した出力:

/tmp/tmp.XXXX/.bash_history: 行 2
/tmp/tmp.XXXX/.bash_history: 行 4
確認おわり(何も出なければ該当なし)

出た行は sed -n '2p' ~/.bash_history などで自分の目で確かめてください(画面に値が出るので、画面共有中は避けます)。

まとめ

  • export や curl -H に直接書いたキーは ~/.bash_history に平文で残る(実機)。
  • 先頭スペースで防げるのは HISTCONTROL に ignorespace/ignoreboth があるときだけ(実機・bash公式)。
  • 打った直後なら history -d -2。-1 では消えない(実機・bash公式)。
  • キーは read -rs で入れる。AIエージェントには履歴ファイルも読ませない。

AIエージェントの手元で .env が読めるかどうかは、ai-secret-check(npx github:supportapp3-lab/ai-secret-check scan、値は表示せず通信もしません)で点検できます。シェル履歴はまだ点検対象ではありません。

関連記事:

参考(公式):

※ 仕様は 2026-10-23 時点の公式ドキュメントに基づきます。検証は GNU bash 5.2.37 で、Linux の使い捨て環境でのみ行いました。

更新情報やちょっとしたTipsは X(@supportapp3_lab)で発信しています。

1
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
1
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?