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

起動中の開発サーバーの環境変数は /proc/PID/environ から読める:.env を消しても残る、Codex のサンドボックスからは見えなかった(Linux 実機)

0
Posted at

この記事の要点

  • Linux では、同じユーザーで動いているプロセスの起動時の環境変数を /proc/<PID>/environ や ps eww で読めます。.env を読み込んでから起動した開発サーバーの OPENAI_API_KEY(ダミー値)が、そのまま表示されました。
  • 起動後に .env を消しても、動いているプロセスからは読めました。消すなら、プロセスの再起動まで必要です。
  • 別のユーザー(nobody)からは Permission denied で読めませんでした。
  • Codex(codex-cli 0.165.0)の codex sandbox で試すと、:read-only と :workspace ではサンドボックスの外のプロセスが見えず、読めませんでした。:danger-full-access では読めました。
  • 自分のプロセスのうち、鍵らしい名前の環境変数を持つものを値を出さずに一覧するスクリプトを載せます。

背景

AI コーディングエージェントに .env を読ませない設定(Claude Code の permissions.deny、Codex の permission profile の deny など)は、ファイルを読ませない設定です。
一方、.env の中身は、開発サーバーを起動した時点でそのプロセスの環境変数に入っています。エージェントがシェルのコマンドを実行できるなら、ファイルではなく、動いているプロセスから読めるのではないか、というのが今回の疑問です。

確かめた環境

  • Debian GNU/Linux 13 (trixie)、kernel 6.12.94、procps-ng 4.0.4
  • codex-cli 0.165.0(npm の @openai/codex)。CODEX_HOME は使い捨てのディレクトリにしました
  • 値はすべてダミーです。筆者の環境変数が混ざらないよう、env -i で空にした環境から始めました
  • 開発サーバーの代わりに、.env を読み込んでから sleep を起動しました

試していないこと

  • macOS・Windows(macOS には /proc がありません)
  • Claude Code・Cursor など、Codex 以外のエージェント
  • ログインした Codex 本体(エージェントのセッション)が実行するコマンド。今回はログイン不要の codex sandbox だけで試しました

1. 公式の説明(man ページ)

Linux の man ページ proc_pid_environ(5) には、次のように書かれています。

This file contains the initial environment that was set when the currently executing program was started via execve(2).

Permission to access this file is governed by a ptrace access mode PTRACE_MODE_READ_FSCREDS check; see ptrace(2).

つまり、中身は起動したときの環境変数で、読めるかどうかは ptrace と同じ種類の権限チェックで決まります。

2. 同じユーザーなら読める

.env を set -a で読み込んでから、プロセスを起動しました。

printf 'OPENAI_API_KEY=dummy-openai-0001\nDB_PASSWORD=dummy-db-0002\n' > .env
( set -a; . ./.env; set +a; exec sleep 300 ) &
$ ls -l /proc/120932/environ
-r-------- 1 box box 0 Oct 30 05:16 /proc/120932/environ
$ tr '\0' '\n' < /proc/120932/environ | grep -E 'OPENAI|DB_'
DB_PASSWORD=dummy-db-0002
OPENAI_API_KEY=dummy-openai-0001

ps eww でも見えました。

$ ps eww -p 120932 | grep -o 'OPENAI_API_KEY=[^ ]*'
OPENAI_API_KEY=dummy-openai-0001

3. .env を消しても、動いているプロセスには残る

$ rm .env
$ tr '\0' '\n' < /proc/120932/environ | grep -E 'OPENAI|DB_'
DB_PASSWORD=dummy-db-0002
OPENAI_API_KEY=dummy-openai-0001

ファイルを消しても、プロセスの環境変数は変わりません。

4. 別のユーザーからは読めない

$ sudo -u nobody cat /proc/120932/environ
cat: /proc/120932/environ: Permission denied

ファイルの権限は -r--------(持ち主だけ読める)で、別ユーザーからは読めませんでした。エージェントを別のユーザーで動かせば、このファイルは読めないことになります。

5. 起動後にプログラムの中で読み込んだ値は出ない(ただし子プロセスには渡る)

man ページには、起動後にプロセスが自分の環境変数を変えても(putenv(3) など)このファイルには反映されない、とも書かれています。Python で試しました。

python3 -c 'import os,time; os.environ["LATE_SECRET"]="dummy-late-0003"; time.sleep(300)' &
$ tr '\0' '\n' < /proc/120952/environ | grep -c LATE_SECRET
0

このプロセスの environ には出ませんでした。一方、同じように値を入れてから子プロセス(sleep)を起動すると、子プロセスの environ には出ました。

$ tr '\0' '\n' < /proc/<子プロセス>/environ | grep LATE_SECRET
LATE_SECRET=dummy-late-0003

python-dotenv のように、プログラムの中で .env を読み込む方式でも、そのあとに起動したコマンドやワーカーのプロセスからは読めると考えられます(推測。python-dotenv そのものでは試していません)。

6. Codex のサンドボックスからは見えなかった

Codex には :read-only・:workspace・:danger-full-access の3つの組み込み permission profile があります(公式 "Permissions")。codex sandbox -P <profile> で、それぞれから同じプロセスの environ を読みました。

$ codex sandbox -P :read-only -- sh -c "tr '\0' '\n' < /proc/120932/environ | grep -E 'OPENAI|DB_'"
sh: 1: cannot open /proc/120932/environ: No such file
$ codex sandbox -P :workspace -- sh -c "tr '\0' '\n' < /proc/120932/environ | grep -E 'OPENAI|DB_'"
sh: 1: cannot open /proc/120932/environ: No such file
$ codex sandbox -P :danger-full-access -- sh -c "tr '\0' '\n' < /proc/120932/environ | grep -E 'OPENAI|DB_'"
DB_PASSWORD=dummy-db-0002
OPENAI_API_KEY=dummy-openai-0001

:read-only と :workspace では「No such file」でした。サンドボックスの中から見えるプロセスの数を数えると、外の 163 に対して 5 でした。

$ codex sandbox -P :workspace -- sh -c 'ls /proc | grep -E "^[0-9]+$" | wc -l'
5

Codex のリポジトリにある Linux サンドボックスの README には、bubblewrap を使い、既定で PID 名前空間を作る(--unshare-pid)と書かれています。外のプロセスが見えなかったのはこのためと考えられます(推測)。

ただし同じ README には、新しい /proc のマウントが拒否された環境では元の /proc をそのまま使う、とも書かれています。また、専用環境向けに PID 名前空間を分けない起動オプション(--linux-sandbox-pid-namespace=inherit)もあると書かれています。環境によっては結果が変わる可能性があるので、自分の環境で一度 codex sandbox -- ls /proc を試すのが確実です(推測)。:danger-full-access は公式の説明どおりサンドボックスの制限を外すので、外のプロセスも読めました。

なお、前回の記事で扱った shell_environment_policy は、Codex が起動するコマンドに渡す環境変数を絞る設定です。ほかのプロセスの environ を読めるかどうかとは別の話です。

7. 点検:鍵らしい名前の環境変数を持つ自分のプロセスを、値を出さずに一覧する

値は表示せず、名前だけを出します。

check_environ.sh
#!/bin/bash
# 自分のプロセスの起動時の環境変数から、鍵らしい「名前」だけを出す(値は出さない)
printf '%-8s %-16s %s\n' PID COMMAND NAMES
for d in /proc/[0-9]*; do
  [ -O "$d" ] || continue
  names=$( { tr '\0' '\n' < "$d/environ"; } 2>/dev/null | cut -d= -f1 | grep -iE 'KEY|SECRET|TOKEN|PASSWORD' | sort -u | paste -sd, -)
  [ -n "$names" ] && printf '%-8s %-16s %s\n' "${d#/proc/}" "$(cat "$d/comm" 2>/dev/null)" "$names"
done

実行例(今回の確認用プロセスの行だけを抜き出しています):

PID      COMMAND          NAMES
120932   sleep            DB_PASSWORD,OPENAI_API_KEY
120958   sleep            LATE_SECRET

ここに出たプロセスは、同じユーザーで動くエージェントがシェルを使えるなら、値を読める状態だと考えられます(推測。Codex の :danger-full-access では実際に読めました)。

8. どうするか

確かめた事実から言えるのは次の3つです。

  • .env を消しても、起動中のプロセスには残ります。止めるか再起動するまで残ります。
  • 別のユーザーからは読めませんでした。
  • Codex の :read-only / :workspace では、外のプロセスは見えませんでした。

ここから、次の使い方がよいと考えます(推測)。

  • Codex は :danger-full-access で使わない。
  • サンドボックスなしでシェルを実行するエージェントを使うときは、鍵を読み込んだ開発サーバーを同じユーザーで動かしたままにしない。分けられるなら、エージェントを別ユーザーやコンテナで動かす。
  • ときどき上の check_environ.sh で、鍵らしい名前を持つプロセスが残っていないかを見る。

まとめ

  • Linux では、同じユーザーのプロセスの起動時の環境変数は /proc/<PID>/environ と ps eww で読めました。.env を消しても残りました。
  • 別ユーザーからは読めませんでした。
  • Codex(0.165.0)の codex sandbox では、:read-only・:workspace から外のプロセスは見えず、:danger-full-access では読めました。

参考

※ 仕様は 2026-10-30 時点の公式ドキュメントに基づきます。動作は Linux の使い捨て環境で、ダミー値と codex sandbox を使ってのみ試しました。

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

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