credential-leakmajorverifiedfirsthand
APIキーが設定されているかを、値を明かさずに確認するはずのシェルの一行が、キー全体を画面とセッションのログにそのまま出力した。
原因: ${VAR:+設定あり}${VAR:-未設定} という式は、『2つのステータスの単語のどちらかしか出力されない』という思い込みで書かれていた。実際には:-は未設定のときだけ代替値を返す構文であり、変数が設定されている場合は代替の文言ではなく変数の実際の値そのものに展開される。
結果: APIキー全体がターミナルとセッションログの両方に出力され、即座のローテーションが必要になった。
対策: 有無だけを確認するなら [[ -n "$VAR" ]] を使う。長さを示すなら ${#VAR}。どのキーかを識別する程度でよければ末尾数文字 ${VAR: -4} にとどめる。秘密情報に触れうるコマンドを実行する前に、その式を一度読み返し『これは値そのものを出力しうるか』を自問する。
何が起きたか
AIコーディングエージェントとシェル上で作業している最中、「このAPIキーは
設定されているか?」を確認するつもりで ${VAR:+設定あり}${VAR:-未設定}
という式を書いた。出力されたのはキーそのものだった。
現場の混乱
一見して問題なさそうに見え、「テスト」は通ったように見えた——出力の見た目には エラーらしきものは何もなかった。この漏えいは自動チェックでは捕まらず、 実際にターミナルの出力を目で見た人によって発見された。
原因
${VAR:-代替値} は、VARが未設定または空のときにだけ代替値を返す。
VARが設定されている場合は、VARの実際の値そのものに展開される——
プレースホルダーでも、伏せられたバージョンでもなく、値そのものである。
この式は逆の挙動を期待して書かれていた。つまり、常にステータスを示す
単語だけが表示され、確認対象の秘密情報そのものは決して表示されない、
という思い込みである。
対策
有無の確認には [[ -n "$VAR" ]] && echo あり || echo なし を使う——
これは変数を出力に展開することが決してない。完全に晒さずに識別したい
場合は、長さ(${#VAR})か、UIが通常表示する粒度に合わせた末尾の短い
切り出し(${VAR: -4})を使う。秘密情報に触れるシェル式を実行する前には
必ず一度読み返し、『どんな条件でこれは値を出力するか』を直接問う。