そのワードリストはあなたのホームディレクトリを知っていた
F5 Labs は一か月で、露出した Vite 開発サーバーに対する 807 件の攻撃と 32,000 件のイベントを記録した。使われたのはクエリ文字列の小細工で、Vite 自身の deny-list の前を素通りする。スキャナーはあなたのアプリを探してはいない。/home/ubuntu/.aws/credentials を絶対パスで要求し、/proc/self/environ を要求し、terraform.tfstate を要求する。Bromure Agentic Coding のワークスペースでは、そのポートはプライベートなスイッチに面しており、ワードリストが欲しがるファイルには鍵など入っていない。
この攻撃者はパッケージもアーカイブも送ってこない。待ち受けているのはあなた自身の 開発サーバーで、見知らぬ相手がファイルを名指しで要求する。どのマシンが答えるかが、 相手の得るものを決める。
フロントエンドを見たいので、エージェントに立ち上げるよう頼む。エージェントは
npm run dev と打ち、ポートを開き、ページを読み込み、あなたは差分のレビューに戻る。
そのループのどこかで、docker-compose.yml の中か、スマートフォンからプレビューを
見るために何週間も前に付けた --host フラグの中で、サーバーはループバックではなく
全インターフェースにバインドしていた。十二分後、Googlebot を名乗る何かがあなたの
開発サーバーに /@fs/../.env?raw?? を要求し、HTTP 200 を受け取る。
F5 Labs は 9 月 11 日に数字を公開した。 2026 年 8 月というたった一か月のセンサーデータの中で、同社のハニーポットは、露出した Vite 開発サーバーを狙うセッション単位の攻撃 807 件と、およそ 32,000 件の生イベントを 記録した。直前の三か月で 1,732 件という基準値に対してである。たった一つのバグのために、 前月比で十八倍のトラフィックということだ。BleepingComputer は 9 月 14 日に報じている。
deny-list の脇をすり抜けるクエリ文字列
Vite は /@fs/ という内部ルートを通じてホストのファイルシステムからファイルを配信する。
プロジェクトルートの外にあるモジュールを開発サーバーがエディタへ渡すための仕組みだ。
このルートはどこへでも手が届くので、Vite は明らかな標的を塞ぐために server.fs.deny
という deny-list を同梱している。.env ファイル、証明書、非公開のソースである。
4 月 7 日に公開された CVE-2026-39364 は、リクエストにクエリ文字列を飾り付けるだけで、 攻撃者にその deny-list を跳び越えさせる。F5 はその仕組みをこう記述する。
サーバーはリクエストを処理してパスを正規化し、アクセス検証の最中にクエリ文字列を 削除するか誤って解釈し、server.fs.deny の検査を発動させそこねる。
サーバーは deny-list によるフィルタリングを適用せず、対象のファイルを HTTP 200 応答とともに配信する。
このバグは Vite 7.1.0 から 7.3.2 まで、および 8.0.5 より前の 8.x に影響する。F5 は
実際の攻撃で次のリクエスト形を捕捉した。どれも一行で読める短さだ。
GET /@fs/.env?raw??、GET /@fs/../.env?raw??、
GET /@fs/..%252f..%252f..%252f..%252froot/.env?raw??、そして
GET /@fs/..%252f..%252f..%252f..%252fproc/self/environ?raw??。同じ道具立ての別の
変種は ?import&raw、?import&url&inline、?inline&import、?raw?import を使う。
そうしたパラメータの小細工にはそれぞれ CVE 番号が付いている。CVE-2025-30208、
CVE-2025-31125、CVE-2024-45811 という、同じスキャナーに今も積まれたままの三つの古い
@fs 回避だ。スキャン網を回している者は、新しいバグのために道具を作り直したのではない。
すでに持っていたファイルに、もう一行足しただけである。
ワードリストは開発者のマシンの地図である
スキャナーが何を求めているかを読み、そのうちどれほど少ない部分しかあなたのアプリに 関係していないかに気づいてほしい。
彼らは .env、.env.local、.env.production、.env.development、
.env.staging を求める。terraform.tfstate、terraform.tfvars、
.terraform/terraform.tfstate、serverless.yml、
.serverless/serverless-state.json を求める。.azure/credentials と
.azure/accessTokens.json を求める。/etc/passwd、/proc/1/environ、
/proc/self/cwd/.env、/proc/self/environ を求める。最後のパスは開発サーバー
プロセス自身の環境ブロックであり、シェルが export した API_KEY が行き着く先だ。
そして彼らは、開発者のプロセスが動いていそうなホームディレクトリを順に当たりながら、 AWS の資格情報を求める。
/root/.aws/credentials、/home/ec2-user/.aws/credentials、
/home/ubuntu/.aws/credentials、/home/node/.aws/credentials、
/home/www-data/.aws/credentials、/home/admin/.aws/credentials、
/home/debian/.aws/credentials、/var/www/.aws/credentials、
/usr/src/app/.aws/credentials、/app/.aws/credentials。続いて .aws/config、
.aws/credentials.backup、.aws/credentials.bak、.aws/sso/cache/、
rootkey.csv、aws-exports.js、amplifyconfiguration.json。
これらのパスは、ユーザー名で列挙された開発者マシンの棚卸しであり、Vite はただの扉に すぎない。バグは付随物で、同じルートの三つの古いバグが同じリクエストに相乗りしている。 運用者が賭けているのは、ルーティング可能なアドレスで待ち受けるプロセスが、ホーム ディレクトリに本物の鍵を抱えたユーザーとして動いている、という一点だ。
トラフィックは、ログをざっと眺めただけでは見逃されるように着飾っている。F5 が記録した
偽装 User-Agent ヘッダーは Googlebot/2.1、ClaudeBot/1.0、GPTBot/1.4、
PerplexityBot/1.0、OAI-SearchBot/1.3、Amazonbot/0.1 を巡回し、さらに IP
許可リストを抜けるために X-Forwarded-For と X-Real-IP の値も偽装されていた。送信元は
Google Cloud の 34.x と 35.x のレンジに複数リージョンにまたがって並び、首位は
アメリカ合衆国の 17,297 イベント、次いでベルギーの 4,407、オランダの 4,011 だった。
今月に限れば、アクセスログの中で AI クローラーを名乗る一行は、それをクローラーが
送った証拠としては心もとない。
F5 の推奨のうち二つはアーキテクチャの問いである
F5 は五つの助言で締めくくる。三つはありふれていて正しい。7.3.2 か 8.0.5 に更新する、
エッジで /@fs/ を遮断する、ヘッダーを信用せず逆引き DNS でクローラーを検証する。
残る二つは、終わらせられる作業ではなく、保ち続けなければならない姿勢を述べている。
開発サーバーが外部インターフェースにバインドしないようにすること。Docker compose の構成、Kubernetes の ingress ルール、クラウドのセキュリティグループを監査すること。
露出した秘密を更新すること。未修正の Vite 開発サーバーが 2026 年 8 月に外部 ネットワークから到達可能だったなら、ローカルの .env 変数、AWS の資格情報、Azure の アクセストークン、Terraform の状態ファイルを侵害された可能性があるものとして扱うこと。
一つ目は、あらゆるポートについて、あらゆる compose ファイルの中で、あらゆるブランチに
わたって、プロジェクトが生きているかぎり約束を守れと求める。しかも npm run dev を
打つのが、あなたではなくエージェントであることが多い時代にである。二つ目はその後に何を
するかを問い、こう答える。マシンが見えていたものを更新せよ、と。
どちらも、ポートが別の場所で開き、ワードリストが名指すファイルに更新する価値のあるものが 何も入っていなければ、ずっと楽になる。
Bromure のワークスペースはポートをどこに置くか
Bromure Agentic Coding は、あなたの Mac 上のハードウェア仮想化された Linux VM の中で コーディングエージェントを動かし、セキュリティ制御はその境界のホスト側に置く。この キャンペーンに答えるのはそのうち二つだ。
開発サーバーはプライベートなスイッチの内側でバインドする。 既定の NAT モードでは、
各ワークスペース VM は単一の vmnet インターフェース上に多重化された、プロセス全体で
一つのソフトウェア L2 スイッチに接続され、プライベートなサブネットに置かれる。その
サブネットは、あなたの LAN が既に使っていないかぎり 192.168.64.0/24 であり、Bromure
はそこで自前の DHCP サーバーを動かし、各ワークスペースは決定的な MAC と安定したリースを
保つ。マニュアルはその帰結をこう述べる。あなたの Mac は VM に届き、物理 LAN からは VM が
見えず、自分でサービスを公開しないかぎり外部からの受信接続は不可能である、と。その VM の
中で 0.0.0.0 にバインドしたエージェントは、自分の持つすべてのインターフェースに
バインドしたのであり、そのどれもがあなたのラップトップで始まり終わるスイッチに面している。
監査すべきセキュリティグループは存在しない。守るべき入り口の経路が存在しないからだ。
それでも何が待ち受けているかは見える。しかもそれは監査ではなく一覧である。
ワークスペースのダッシュボードには Listening Ports カードがあり、ゲスト内で外部から
到達可能なソケットを <VM の IP>:<ポート> というエンドポイントとして、ワンクリック
コピー付きで並べる。これは F5 の推奨その 2 を、予定に組み込む監査ではなく、ちらりと
目をやるカードに変える。更新はゲストから 1.5 秒ごとだ。本当に世界にプレビューを見せたい
ときは、HTTP らしきサービスに地球儀ボタンが付き、一度きりの同意ダイアログの向こうで、
Cloudflare のクイックトンネル経由でそのサービス一つだけを公開する。公開はホスト上で
サービスごとにクリックして行うのであって、compose ファイルにフラグを生かしたままに
することではない。
そもそも --host に手を伸ばした理由の方は、そのまま残る。使い捨ての Chromium
サイドカーはワークスペース VM と同じ L2 セグメントを共有するので、組み込みブラウザは
エージェントの開発サーバーを VM のアドレスで読み込む。ブラウザは別のマシンで動くので、
localhost ではない。
他のマシンから本当に VM に届く必要があるなら、Bridged モードが VM を物理 LAN に加える。 これはホスト上のワークスペースエディタでワークスペースごとに設定し、起動時に インターフェースが使えなければ NAT に戻る。この選択はパネルの中で行うのであって、 エージェントが編集できる設定ファイルの中ではない。
そして意図してサービスを公開するなら
顧客や同僚のために、本当にプレビューをインターネットに出したいこともある。ならば 地球儀をクリックし、トンネルを開き、スキャナーに見つけさせればいい。ワードリストを 一項目ずつ下りながら、何が返ってくるかを見てみよう。
.env と /proc/self/environ はワークスペースの環境を返すが、そこにある資格情報は
どれも偽物だ。Bromure は各プレースホルダーを、本物の値とインストールごとの 32 バイトの
ソルトから HKDF-SHA256 で導出し、クライアント側のバリデータが期待する形は保つ。
Anthropic の鍵は sk-ant-api03-brm-… と読め、GitHub のトークンは ghp_ に 36 文字、
GitLab は glpat- に 20 文字が続く。Bromure はその偽物を環境変数に書き込み、
~/.git-credentials、~/.docker/config.json、~/.kube/config、そして MCP の設定にも
書き込む。本物の値が VM に入ることはない。Mac 上で暗号化されたまま残り、ホスト側の
プロキシが最後の瞬間に一つずつ通信路の上で差し替える。しかも、その値が属する宛先
ホストに限ってである。
/home/ubuntu/.aws/credentials は最も鋭い項目だ。/home/ubuntu は Bromure の
ワークスペース VM のホームディレクトリそのものだからである。スキャナーは、サーバーを
動かしているユーザーを正しく言い当てている。それでもファイルはそこにない。Bromure の
AWS 設定は資格情報ファイルを書かない。書くのは ~/.aws/config であり、そこの
credential_process 行はヘルパーを指す。そのヘルパーはホストのソケット越しに、あなたの
本物のアクセスキー ID と、四十文字の偽のシークレットキーを組にして渡し、セッション
トークンは省く。AWS の SDK も、aws CLI も、terraform も boto3 も、それを自分で拾う。
設定ファイルを読んだスキャナーが手にするのは、自分には呼べないヘルパーのパスだ。
それでも偽のシークレットを持ち去ったなら、持ち去ったのは動かないものである。ゲストは
その偽物でリクエストに署名し、ホストは出ていく途中で署名を剥がして本物の鍵で署名し直す。
他のどんな経路で AWS に届いたリクエストも InvalidSignatureException で失敗する。F5 の
最後の推奨は、ローカルの秘密をすべて侵害されたものとして扱い、更新せよというものだ。
Bromure 自身のドキュメントの対応する一行は、逆向きに読める。漏れたのは偽物だけなので、
本物の資格情報を更新する必要は決して生じない。
ワードリストの一項目は、本当に金銭的価値のあるファイルを名指している。
terraform.tfstate である。状態ファイルはリポジトリのある場所に置かれるので、その
露出を決めるのは共有フォルダの一覧だ。ホストのフォルダはワークスペースに virtiofs の
マウントとして /home/ubuntu/<basename> に取り付き、ワークスペースあたり八つが上限で、
VM が手を届かせられる Mac のファイルシステムはそれだけである。エージェントが作業する
リポジトリだけを共有すれば、トラバーサルが見つけるのはディスクではなく一つの
ディレクトリになる。
今年の開発者向けセキュリティの話のほとんどは、何かが届くことを描いている。パッケージ、 アーカイブ、ドキュメントファイル。ここでは何も届かない。代わりに、月 32,000 件の リクエストが、あなたが起動したプロセスに向かって、見知らぬ相手へファイルを読み上げろと 求める。そして結末を決めるのは、そのプロセスを動かしているのがどのマシンで、その ホームディレクトリに何が置かれているかである。
エージェントの開発サーバーを、あなたの Mac だけがいるスイッチに置き、そのホーム ディレクトリを偽物で満たそう。 Bromure Agentic Coding をインストールして、あとはスキャナーに 尋ねさせればいい。