Baseten を inference の提供元として使おうとしていたセキュリティ企業 Strix が、公開されていた Docker/Harbor 系のイメージを自動調査したところ、古い GitHub personal access token を見つけた、というのがこの話の骨子だ。しかもそのトークンは生きていて、Baseten の内部 GitHub リポジトリに対して admin 権限を持っていたとされる。外部サービスを業務に組み込む前に、相手側の足元を自分で点検する。その重要性をかなり生々しく示した事例だと思う。
Strix は自社の自律型ハッキングエージェントを使い、*.baseten.co を対象にクレデンシャルなし、ソースコードなしで調査を走らせた。Baseten は推論基盤を提供する企業で、Strix は自分たちのデータやモデル、コードを預ける前に、まず相手のセキュリティを確認したかったという。調査を始めて約25分後、Strix は Baseten の GitHub personal access token を見つけたと主張している。
最初の入口は Harbor というコンテナイメージのレジストリだった。Strix はホスト列挙や証明書ログの確認を進め、gcp-us-east4-zlw.registry.baseten.co に到達した。Harbor には public な project があり、認証なしで repository 名の一覧取得、匿名 pull token の取得、manifest と blob のダウンロードができたという。その中に baseten/baseten-app というイメージがあった。
ここで終わらせず、Strix は中身を確認した。最初に出てきた AWS キーは無効だったが、さらに掘ると image config の history[].created_by に GitHub の personal access token が残っていた。Docker image はファイルシステム層だけでなく、ビルド履歴も持っている。その履歴に、GITHUB_TOKEN を展開した RUN コマンドが記録されていた、という説明だ。Strix がその token で GitHub の GET /user を叩くと、basetenbot というアカウントで 200 が返った。
問題は、そこで見つかった token が「生きていた」ことだ。GitHub の応答ヘッダには repo スコープがあり、アカウントは basetenlabs 組織に所属していた。さらに repository ごとの権限を確認すると、Baseten の main product repo には admin と push 権限、GitOps repo には admin と push 権限、Homebrew tap にも admin と push 権限があったほか、複数の private repository に read/write が付いていたという。中には顧客ごとの private repo らしきものも含まれていた。
Strix は、ここで手を止めた。顧客 repo を clone したり、何かを書き換えたりはしていない。すぐに disclosure のメールを送り、Baseten 側も critical と認定して token を rotate し、Harbor project を private にした。本文では、build history に残った token の step が 2023年3月3日に実行され、Strix が確認したのは2026年7月だと書かれている。つまり、3年以上前の build credential が、まだ大きな権限を持ったまま放置されていたことになる。
原因として挙げられているのは、private dependency を取得するために build argument で GITHUB_TOKEN を渡し、それを git config --global に書いてしまう、よくあるパターンだ。Docker は build argument を image の metadata や history に記録してしまうことがあり、しかも git config --global は認証済み URL を設定ファイルに残す。対策としては BuildKit の secret mount を使い、credential を image に永続化しないこと、それから既に出回った image を前提に token 自体も revoke することが必要だと述べている。
まず引っかかるのは、漏れたのがコードではなく Docker の build history だった点だ。多くの人は「秘密情報を image に入れない」と聞くと、.env や設定ファイルを消す話を想像する。でも実際には、削ったつもりの痕跡が metadata に残る。しかもそれを回収するのは、ファイルを消すより面倒だ。今回のように history[].created_by を見ないと分からないケースは、一般的なイメージスキャンだけでは見逃しやすい。ここはかなり現実的な怖さがある。
次に重いのは、token の権限が大きすぎたことだと思う。repo スコープの GitHub token 自体は珍しくないが、問題はそれが product repo、GitOps repo、Homebrew tap にまで広く効いていたことだ。単なるソースコード閲覧では終わらず、開発から配布、さらには運用までつながる。GitOps repo に触れれば production infrastructure の望ましい状態に手が届くし、配布経路をいじれば supply chain の問題になる。秘密の漏えいが、権限設計の甘さで一気に重症化している。
この話で面白いのは、Strix が最初から「これが危ないはずだ」と決め打ちしていないことだ。Harbor を見つけ、匿名で pull できるか確認し、AWS キーが死んでいれば次を探し、build history の中の token にたどり着き、その token が何に効くかまで確かめている。人間の手でやると、最初の露出が見つかった段階でレポートを書いて終わりにしがちだが、実際のリスクはそこで終わらない。何に使える秘密なのか、どこまで権限があるのかが本体だからだ。
ここは AI の「速さ」より「粘り」が効いた例だと思う。しかも、Baseten のような成熟した会社でも、古い build の痕跡が残っていた。つまり問題は一社の怠慢というより、コンテナ運用のどこでも起きうる。依存取得のために token を渡す、BuildKit を使わず昔ながらの書き方を続ける、古い image を誰も見返さない。そうした小さな積み重ねが、数年後に admin 権限つきの漏えいとして表に出る。これはかなり多くのチームに刺さるはずだ。
Baseten 側の動きは速かった。公開された本文では、報告の翌朝に Harbor project を private にし、その日のうちに critical と認定して token を rotate している。こういう場面では、初動が遅いと話が一気に悪化する。そこは素直に評価できる。一方で、対応が速かったことと、根っこが解決したことは別だ。古い build image がどこまで残っているのか、誰がいつ pull したのか、token と image の切り離しが本当にできているのかまでは、この話だけでは見えない。
だから教訓は「秘密を隠しましょう」で止まらない。build に使う credential は短命にする、必要最小限の権限に絞る、build history と layers の両方を確認する、公開レジストリを定期的に洗う。さらに言えば、外部ベンダーを選ぶ側も、SLA や機能だけでなく、こうした運用の癖まで見たほうがいい。推論基盤のように自社データに触れるサービスならなおさらだ。セキュリティレビューを先にやるのは面倒だが、今回のように実害が出うる以上、やらない理由のほうが薄い。