結論
- API キーを コマンドの引数に直接書くと、同じマシンの別ユーザーからも
psで丸見えになります(2026-11-08、Debian 13・procps-ng 4.0.4・ダミー値で実機確認)。curl -H "Authorization: Bearer ..."も--api-key=...も、そのまま出ました。 - 一方、環境変数に入れた値は、別ユーザーからは
/proc/PID/environが Permission denied で読めませんでした(同じユーザーなら読めます)。 -
curl -u user:passはps上で*****に隠されました。ただし curl 公式マニュアルは「隠れるまでの一瞬は見える」と書いています。-Hは隠されません。 -
curl -H @ファイルにすると、psに出るのはファイル名だけでした。
この記事は「AIエージェントと秘密情報」の検証シリーズです。新しい検証は X(@supportapp3_lab)でもお知らせしています。
試してみる(鍵を引数に書いていないか)
いま動いているプロセスの引数に、鍵らしい文字列が入っていないかを見ます(値は自分の画面にだけ出ます)。
ps -eo user,pid,args | grep -iE 'bearer|api[-_]?key|token|password|secret' | grep -v grep
スクリプトや AI に書かせたコマンドに残っていないかは、こちらで探せます。
grep -rnE --include='*.sh' --include='*.bash' --include='Makefile' --include='*.yml' \
-- '-H[[:space:]]+["'"'"']?Authorization:[[:space:]]*Bearer[[:space:]]+[A-Za-z0-9]|--(api[-_]?key|token|password)=' .
.env 系のファイル名だけ先に見たい場合は、読み取り専用の CLI もあります。
npx github:supportapp3-lab/ai-secret-check scan
リポジトリ: https://github.com/supportapp3-lab/ai-secret-check
実機で確かめたこと
値はすべてダミーです。ローカルに6秒かけて返事をするだけの HTTP サーバーを立て、その間に box ユーザーで次の4つを動かし、別ユーザー nobody から ps と /proc を見ました。
export DUMMY_API_KEY=sk-dummy-ENV-0000
curl -s -H "Authorization: Bearer sk-dummy-ARG-1111" http://127.0.0.1:18080/ &
curl -s -u "user:sk-dummy-USER-2222" http://127.0.0.1:18080/ &
curl -s -H @hdr.txt http://127.0.0.1:18080/ & # hdr.txt は chmod 600
python3 -c 'import time; time.sleep(6)' --api-key=sk-dummy-PY-3333 &
1. 別ユーザーの ps
sudo -u nobody ps -eo user,args
box curl -s -H Authorization: Bearer sk-dummy-ARG-1111 http://127.0.0.1:18080/
box curl -s -u *********************** http://127.0.0.1:18080/
box curl -s -H @hdr.txt http://127.0.0.1:18080/
box python3 -c import time; time.sleep(6) --api-key=sk-dummy-PY-3333
-
-Hで渡した Bearer トークンと--api-key=は、別ユーザーからそのまま読めました。 -
-uの値は*に置き換わっていました。 -
-H @hdr.txtは、ファイル名しか出ません。
2. 別ユーザーの /proc/PID/cmdline と environ
$ sudo -u nobody cat /proc/<PID>/cmdline
python3 -c import time; time.sleep(6) --api-key=sk-dummy-PY-3333
$ sudo -u nobody cat /proc/<PID>/environ
cat: /proc/<PID>/environ: Permission denied
同じ box ユーザーからは environ に DUMMY_API_KEY=sk-dummy-ENV-0000 が見えました(/proc/PID/environ の記事と同じ結果)。
つまりこの環境では、引数は別ユーザーにも見え、環境変数は同じユーザーにしか見えないという差がありました。
公式の説明
- Linux man-pages の
proc_pid_cmdline(5):/proc/pid/cmdlineは「プロセスの完全なコマンドライン」を持つ読み取り専用ファイル、と書かれています。 -
proc(5)のhidepid=n(Linux 3.3 以降):/proc/pidディレクトリの情報に誰がアクセスできるかを決めるマウントオプションです。今回の環境は/procにhidepidが付いていない状態(mountで確認)でした。 - curl 公式マニュアルの
-u, --userと-U, --proxy-user:「On systems where it works, curl hides the given option argument from process listings. This is not enough to protect credentials ... as they still are visible for a moment before being cleared.」と書かれ、ファイルなどから読むよう勧めています。この説明は-uと-Uの項目にあり、-Hの項目にはありません。今回の実機でも-Hは隠れませんでした。
AIエージェントとの関係(ここからは推測を含みます)
- AI に「この API を curl で叩いて」と頼むと、
-H "Authorization: Bearer <キー>"の形でキーを直接書いたコマンドが作られることがあります(推測。今回はエージェント経由では試していません)。 - 共用の VPS や、ほかのユーザーやサービスアカウントが動いているサーバーでは、その数秒〜数分の間に
psから読まれる可能性があります(推測。1人で使うマシンなら影響は小さいと考えられます)。 - 引数に書いたキーは、シェル履歴にも残ります(シェル履歴の記事で実機確認済み)。
対策
- curl のヘッダーは
-H @ファイル(ファイルはchmod 600)で渡す。ファイル名しかpsに出ませんでした。 - 自作スクリプトは、キーを引数ではなく環境変数やファイルから読む。別ユーザーからの
environは読めませんでした(同じユーザーからは読めるので万能ではありません)。 -
curl -uの*隠しは、公式どおり「一瞬は見える」前提で扱う。 - 共用サーバーでは、
/procのhidepid=2などで他ユーザーのプロセス情報を隠す方法があります(proc(5)。今回は共有環境のため設定変更は試していません)。 - AI にコマンドを作らせるときは「キーは引数に書かず、ファイルか環境変数から読む形で」と条件を付ける。
ai-secret-check について
ai-secret-check scan は、AIが読めそうな場所にある .env 系のファイル名を探します(中身は表示しません)。引数に書かれたキーまでは見ないので、上の ps / grep とセットで使ってください。
npx github:supportapp3-lab/ai-secret-check scan
リポジトリ: https://github.com/supportapp3-lab/ai-secret-check (Node.js 20以上、MIT)
参考
- Linux man-pages: proc_pid_cmdline(5) https://man7.org/linux/man-pages/man5/proc_pid_cmdline.5.html
- Linux man-pages: proc(5)(hidepid) https://man7.org/linux/man-pages/man5/proc.5.html
- curl man page(
-u, --user/-U, --proxy-user) https://curl.se/docs/manpage.html - 関連: /proc/PID/environ / シェル履歴に export が残る / bash -x で鍵が出る
※ 2026-11-08 に、Debian 13(カーネル 6.12)・curl 8.14.1・procps-ng 4.0.4・Python 3.13.5、ダミー値で確かめました。
更新情報やちょっとしたTipsは X(@supportapp3_lab)で発信しています。