那份字典檔早就知道你的家目錄
F5 Labs 在一個月內記錄到針對暴露的 Vite 開發伺服器的 807 次攻擊與 32,000 筆事件,用的是一個查詢字串小把戲,直接從 Vite 自己的 deny-list 前面走過去。掃描器要找的不是你的應用程式。它們用絕對路徑索取 /home/ubuntu/.aws/credentials,索取 /proc/self/environ,索取 terraform.tfstate。在 Bromure Agentic Coding 的工作區裡,那個連接埠面對的是一台私有交換器,而字典檔想要的那個檔案裡沒有任何金鑰。
這個攻擊者不寄套件給你,也不寄壓縮檔。是你自己的開發伺服器在聽,而一個陌生人 直接點名向它要檔案。由哪一台機器回答,決定了對方拿到什麼。
你叫代理把前端跑起來,好讓你看一眼。它敲下 npm run dev,綁好連接埠,載入頁面,
你則回頭去看那份 diff。在那個循環的某處,在某個 docker-compose.yml 裡,或在你
幾週前為了讓手機也能看預覽而加上的 --host 旗標裡,伺服器綁上了每一張介面,而不是
只綁 loopback。十二分鐘後,某個自稱 Googlebot 的東西向你的開發伺服器索取
/@fs/../.env?raw??,並拿到一個 HTTP 200。
F5 Labs 在 9 月 11 日公布了數字。 在 2026 年 8 月這單單一個月的感測器資料裡,他們的蜜罐記錄到 807 次以工作階段分組的 攻擊,以及大約 32,000 筆針對暴露的 Vite 開發伺服器的原始事件,而前三個月的基準值是 1,732 筆。也就是說,為了一個臭蟲,流量在一個月之間變成十八倍。BleepingComputer 在 9 月 14 日做了報導。
一段從 deny-list 旁邊走過去的查詢字串
Vite 透過一條叫做 /@fs/ 的內部路由,把主機檔案系統上的檔案送出去;開發伺服器就是
靠它,把位於專案根目錄之外的模組交給你的編輯器。正因為這條路由哪裡都到得了,Vite
隨附了一份 deny-list,也就是 server.fs.deny,用來擋掉那些顯而易見的目標:.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,是同一條路由上三個更早的繞道,至今仍裝在同一批掃描器裡。經營這支 掃描艦隊的人並沒有為了一個新臭蟲重新打造工具。他只是在一份早就有的檔案上,再加了 一行。
字典檔是一張開發者機器的地圖
讀一讀掃描器索取的東西,並留意其中有多少其實跟你的應用程式無關。
它們索取 .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。最後那條路徑裝的是開發伺服器行程
自己的環境區塊,也就是你的 shell 匯出的 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 之間輪替,還有偽造的 X-Forwarded-For 和
X-Real-IP 值,用來繞過 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 都接上
同一台行程層級的軟體 L2 交換器,多工在單一 vmnet 介面上,位於一個私有子網路。除非你
自己的區域網路已經用掉,否則那個子網路就是 192.168.64.0/24;Bromure 在上面跑自己的
DHCP 伺服器,每個工作區都保有固定的 MAC 與穩定的租約。手冊寫下了它的後果:你的 Mac
到得了那些 VM,你的實體區域網路看不到它們,而除非你自己發布某個服務,否則從別處進來的
連線根本不可能。在那台 VM 裡綁上 0.0.0.0 的代理,綁的是它自己擁有的每一張介面,而
每一張都面對一台從你的筆電開始、也在你的筆電結束的交換器。你沒有安全群組要稽核,因為
你沒有一條進來的路要守。
你仍然看得到什麼在聽,而那是一份清單,不是一場稽核。 工作區儀表板上有一張
Listening Ports 卡片,把訪客端每一個可從外部觸及的通訊端,以 <VM 位址>:<連接埠>
的端點形式列出,還能一鍵複製。這把 F5 的第 2 條建議,從一場你得排進行事曆的稽核,
變成一張你順手瞄一眼的卡片,而且每一秒半就從訪客端更新一次。當你真的想讓全世界看到
預覽時,一個看起來像 HTTP 的服務會多出一顆地球按鈕,在一次性的同意對話框之後,透過
Cloudflare 快速通道發布那一個服務。你是在主機上,一個服務一個服務地點擊來公開它,
而不是靠一份 compose 檔案裡活著的旗標。
你當初伸手去拿 --host 的理由,仍然保得住。那台用完即丟的 Chromium 側車跟工作區 VM
共用同一個 L2 網段,所以內嵌瀏覽器是用 VM 的位址去載入代理的開發伺服器。不是
localhost,因為瀏覽器跑在另一台機器上。
如果真有其他機器需要連到這台 VM,Bridged 模式會把它接上你的實體區域網路。你在主機上的 工作區編輯器裡逐個工作區設定這件事,而且啟動時若介面不可用,它會退回 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,然後就讓掃描器去問吧。