你只是開了個開發伺服器, 他們卻拿走了 .env 和 terraform.tfstate
Vite dev server 的一個查詢參數就能繞過檔案封鎖清單,F5 Labs 觀察到 8 月起有人在全網掃這個洞撿雲端金鑰。台灣在來源前五名。這跟我們的 Crusader 案是同一門生意。
為什麼現在很紅:The Hacker News 兩天前報導 F5 Labs 的觀測:攻擊者專挑對外開放的 Vite dev server,用 ?raw 之類的參數把 .env、AWS 憑證、terraform.tfstate 直接讀走,還偽裝成 Googlebot、ClaudeBot、GPTBot。
- Vite 7.1.0 到 7.3.2 之前、8.0.5 之前的 dev server,只要用 --host 對外開放,就能靠 ?raw、?import&raw 等查詢參數繞過 server.fs.deny,把 .env、憑證檔讀出來。已於 4 月修補。
- F5 Labs 在 8 月觀察到大規模掃描,來源包含美國、比利時、荷蘭、新加坡、台灣,大量借道 GCP 的 IP 段;目標檔案是 .env、AWS/Azure 設定、terraform.tfstate、serverless.yml、/proc/self/environ。
- 攻擊者偽裝成 Googlebot/ClaudeBot/GPTBot,並塞假的 X-Forwarded-For 騙過 IP 白名單。這是撿鑰匙的生意,跟我們 INC-2026-0827 的 Crusader 節點做的是同一件事。
本篇目錄
發生了什麼
把 Vite 的開發伺服器想成辦公室裡那台「大家都能連」的印表機。它平常只該印你放進佇列的東西,但有人發現:在列印指令後面多加一個奇怪的參數,印表機就會把桌上任何一張紙都印出來,包括寫著密碼的那張。
CVE-2026-39364 就是這樣的東西。Vite 有一個 server.fs.deny 清單,預設擋 .env、*.crt、*.pem 這類檔案。但在受影響版本裡,對 /@fs/ 路徑的請求只要加上 ?raw、?import&raw 或 ?import&url&inline,被擋的檔案就會以 HTTP 200 回來。前提有三個:dev server 用 --host 或 server.host 對外開放、敏感檔案在允許目錄內、而且原本是靠 deny 清單在擋。
這個洞 4 月就揭露並修補了。真正讓它在 9 月上新聞的,是 F5 Labs 觀察到 8 月起有人在全網掃它,而且掃的人很清楚自己要什麼。
- 2026-04Vite 發布 GHSA-v2wj-q39q-566r,修補於 7.3.2 與 8.0.5GitHub Advisory 與 CVE 紀錄。
- 2026-08F5 Labs 觀察到針對對外開放 Vite dev server 的大規模掃描來源集中在美國、比利時、荷蘭、新加坡、台灣;大量使用 GCP 的 34.x/35.x IP 段。
- 2026-08請求鎖定 .env、AWS/Azure 設定、terraform.tfstate、serverless.yml、/proc/self/environF5 Labs 報告列出的目標路徑。
- 2026-09-15The Hacker News 報導,進入主流資安新聞
- 未知有多少台機器實際被讀走憑證、憑證被拿去做什麼報告只描述掃描行為,沒有受害統計。
這次外洩了什麼
F5 Labs 列出的目標路徑,本質上是一張「哪些檔案裡躺著明文憑證」的清單。把它翻譯成服務與用途,你就知道被讀走一個檔案代表交出了什麼。
| 服務 | 憑證類型 | 用途 | 存在形式 | 放在哪 | 權限範圍 | 狀態 |
|---|---|---|---|---|---|---|
| 應用程式會用到的全部第三方服務 | .env 裡的每一組 KEY=VALUE | 資料庫密碼、API token、金流與寄信金鑰,一個檔案全包 | 明文 KEY=VALUE 文字檔,沒有任何加密 | 專案根目錄,也就是 dev server 允許讀取的範圍內 | 等於這個應用程式能做的全部 | 外部事件,沒有受害統計 |
| AWS:IAM 使用者 | access key ID + secret access key | 程式與 CLI 存取 AWS 全部服務 | INI 格式設定檔的 profile 區段 | 開發者家目錄的 .aws 目錄,或專案內的副本 | 依 IAM 政策,最糟是管理員權限 | 外部事件 |
| Azure | 服務主體憑證與訂閱設定 | 存取 Azure 訂閱內的資源 | CLI 設定檔(JSON/INI) | 開發者家目錄的 Azure 設定目錄 | 依服務主體的角色指派 | 外部事件 |
| Terraform 管到的每一個服務 | state 檔裡的明文屬性值 | 記錄整套基礎設施的實際狀態 | JSON。資源屬性裡直接躺著資料庫密碼、金鑰、連線字串 | terraform.tfstate,常被留在專案目錄或 commit 進 repo | 整個環境的拓撲與憑證,是這批目標裡最值錢的一個 | 外部事件 |
| Serverless 平台(Lambda/Functions) | 部署設定裡的環境變數區塊 | 函式執行期要用的 token 與連線字串 | YAML(serverless.yml)的 environment 區段 | 專案根目錄 | 該函式能存取的資源 | 外部事件 |
| 執行中的 dev server 行程本身 | 整包環境變數(/proc/self/environ) | 不必猜檔名與絕對路徑,直接把行程載入的秘密讀走 | 以 NUL 分隔的明文字串 | Linux 行程檔案系統 | 該行程載入的所有秘密,包含只放在環境變數、沒寫進檔案的那些 | 外部事件 |
| 被讀走之後實際發生了什麼 | 不明 | — | — | — | — | 報告只描述掃描行為;受害者通常要等帳單或停權通知才知道 |
證據等級
跟我們的防暴筆記對照
這件事跟 INC-2026-0827 的 Crusader 殭屍網路是同一門生意的兩個環節:
| | Crusader(我們的案子) | Vite 掃描活動(本篇) | |---|---|---| | 工具找什麼 | 542 條路徑:.env、.git/config、service-account.json、JS bundle 內金鑰 | .env、AWS/Azure 設定、terraform.tfstate、/proc/self/environ | | 從哪裡拿 | 任何對外網站的可預測路徑 | 對外開放的 Vite dev server,用查詢參數繞過封鎖 | | 掃描節點 | 用盜來的 GCP 金鑰在受害專案開的 3 台 VM | 大量 GCP IP 段(推論:同樣是別人的專案) | | 撿到之後 | 回傳 C2,變現:開 VM、AI token、寄信 | 未知,但 terraform.tfstate 通常含整套基礎設施的憑證 |
第一課還是那一句:只要 .env 曾經放在任何對外可讀的位置,就當作已外洩處理。Vite 的洞只是又多了一條「對外可讀」的路。
另一個對照是 INC-2026-0915:那台礦機的入口是一個「開發用」Flask 端點,整條對公網開放。Vite dev server 的 --host 是同一種東西:為了方便同事或手機預覽而開的門,忘了關。
攻擊者 vs 防守者
- 正式站有 WAF、有 CDN、有人在看;dev server 三者皆無,而且 .env 就在專案根目錄。
- terraform.tfstate 是大獎:裡面常有資料庫密碼、雲端金鑰、整套基礎設施的拓撲。拿到一份等於拿到整個環境的地圖。
- 偽裝成 Googlebot 或 GPTBot,因為很多人的存取規則對爬蟲特別寬鬆。
- 用別人的雲端專案當掃描節點。被封 IP、被報 abuse 的都不是他。
開發伺服器不是「不重要所以沒關係」,是「沒人看所以最危險」。這是我們三起防暴筆記的共同點,也是這則新聞的重點。
這篇提到的項目要花多少錢
這是外部事件,我們拿不到任何一方的帳單,所以下表沒有一列是可證明的。列出來是為了說明量級:他掃你的成本有多低、你被撿走一把金鑰的代價有多高。
| 項目 | 用量 | 單價 | 期間 | US$ | NT$ | 舉證 |
|---|---|---|---|---|---|---|
| 他掃你一台主機的成本 估:就算自己租機器,掃 100 萬台的頻寬成本也不到 US$1 | 1 個 GET 請求,約 1 KB | 借道別人的雲端專案(推論) | 每台 | 0.00 | 0 | F5 Labs 報告描述的請求形態;「那些專案是被盜用的」是我們的推論 |
| 他的掃描節點:1 台小型 VM 估:若用盜來的金鑰開,這筆記在受害專案的帳上,不是他的 | 24 小時 × 9 天 | US$0.134/機器小時(e2-standard-4 牌價) | 9 天 | 28.94 | 926 | GCP 官方牌價;F5 Labs 沒有公布節點規格與數量 |
| 被讀走的 .env 裡一把管理員 AWS 金鑰 估:量級示意,不是本案的實際損失。他只要撿到一把,一天就把整趟成本賺回來 | 拿去開 1 台 GPU 機 24 小時 | US$32.77/小時(p4d.24xlarge,us-east-1 牌價) | 1 天 | 786.54 | 25,169 | AWS 官方牌價 2026-09;本案沒有受害統計 |
| 被讀走的寄信憑證 估:這一百塊買的是你網域的寄信信譽,信譽掉了不是錢能買回來的 | 冒用你的網域寄 100 萬封釣魚信 | US$0.10/千封(SES 牌價) | 一次 | 100.00 | 3,200 | Amazon SES 官方牌價 2026-09 |
| 今天花 3 小時做完盤點 估:這是本文唯一一列「你可以選擇要不要付」的成本 | 查所有子專案 vite 版本、關掉 --host、列出 .env 裡的金鑰清單 | 顧問日費 NT$27,500(估)/8 小時 | 一次性 | 322.27 | 10,313 | 本站估算的工時;日費為假設值 |
| 事後才補的同一件事 估:數字取自本站防暴筆記〈金鑰已經換了,真的每一把都換到了嗎?〉的人力拆解。同一件事,事前 3 小時,事後 26 小時 | 盤點 4 小時+撤銷切換 6 小時+改建無金鑰架構 2 人日 | 同上 | 一次性 | 2793.00 | 89,376 | 本站 INC-2026-0827 的處置工時;日費為假設值 |
| terraform.tfstate 被讀走之後 它的價值,是讓上面每一列都不必用猜的 | 一份檔案等於整套基礎設施的拓撲與密碼 | — | — | — | — | 沒有任何日誌會告訴你檔案被讀走之後對方做了什麼 |
| 實際被讀走多少憑證、被拿去做什麼 跟大多數掃描活動一樣,受害者通常要等帳單或停權通知才知道 | — | — | 2026-08 至今 | — | — | F5 Labs 報告只描述掃描行為,沒有受害統計 |
| 合計(僅可證明列) | 0.00 | 0 | ||||
重點學習
- 01--host / server.host一行設定決定你的開發伺服器只在自己電腦上,還是在全網。這是本篇唯一真正要改的東西。
- 02.env 視為已外洩只要它曾經落在對外可讀的範圍內,就不要爭論有沒有真的被讀;直接輪替,比事後鑑識便宜。
- 03server.fs.deny這次被繞過的就是它。它是清單式封鎖,本質上永遠在跟繞過方式賽跑,不能當唯一防線。
- 04CVE-2026-39364受影響區間是 7.1.0 ≤ v < 7.3.2 與 8.x < 8.0.5。對照 lockfile 只要一分鐘,是今天最划算的一分鐘。
- 05npm ls vite / pnpm why vite真正在跑的版本藏在傳遞相依裡,package.json 寫什麼不算數。子專案越多越要用它。
- 06/@fs/Vite 用來讀專案外檔案的路徑前綴,也是你在 access log 裡最該 grep 的字串。
- 07terraform.tfstate比 .env 更值錢的目標:一份檔案給出整個環境的地圖與密碼。它不該進 repo,也不該在網站根目錄。
- 08/proc/self/environ 與 /proc/self/cwd攻擊者用它們就不必猜你的專案絕對路徑。請求裡出現這兩個字串,代表對方懂你的部署堆疊。
- 09X-Forwarded-For這是使用者可以自己填的字串。拿它做 IP 白名單,等於把門鎖交給敲門的人。
- 10偽造 User-Agent(Googlebot/ClaudeBot/GPTBot)你為爬蟲放寬的規則,會原封不動變成攻擊者的通行證。UA 不是身分。
今天就可以來試試
全部唯讀,不改任何設定;做完你會知道自己有沒有同樣的破口。
- 看本機與開發主機上,哪些開發埠綁在 0.0.0.0 或 ::。
ss -tlnp | grep -E ':(5173|5174|3000|4173|8080)\b'看到什麼代表什麼:位址是 0.0.0.0 或 :: 代表同網段、甚至整個網際網路都連得到;只有 127.0.0.1 才算安全。 - 查每個專案實際在跑的 vite 版本。
npm ls vite 2>/dev/null | grep vite # pnpm 專案改用:pnpm why vite看到什麼代表什麼:落在 7.1.0 ≤ v < 7.3.2 或 8.x < 8.0.5 就是受影響版本,今天就排升級。 - 找出設定檔裡把 host 打開的專案。
grep -rn --include='vite.config.*' -E "host:\s*(true|'0\.0\.0\.0')" . grep -rn 'vite.*--host' package.json */package.json 2>/dev/null看到什麼代表什麼:命中代表這個專案每次啟動都對外開門,而不是偶爾;這種比忘了關的更危險。 - 若主機有 access log,看有沒有人已經來過。
grep -E '/@fs/.*\?(raw|import&raw|import&url&inline)' /var/log/nginx/*access.log* 2>/dev/null | head看到什麼代表什麼:命中任何一條,就把該專案 .env 裡的每一把金鑰當已外洩,今天輪替,不要先查「有沒有真的被讀到」。 - 列出該專案 .env 的鍵名(只看名字,不看值),當成輪替清單。
cut -d= -f1 /path/to/project/.env | grep -v '^#' | grep -v '^$'看到什麼代表什麼:這個清單的長度,就是「萬一外洩」你今天要處理的工作量。超過十行還沒有人負責,就是本篇講的問題。 - 在 log 裡找自稱爬蟲、來源卻不對的請求。
grep -Ei 'googlebot|gptbot|claudebot' /var/log/nginx/*access.log* 2>/dev/null | awk '{print $1}' | sort | uniq -c | sort -rn | head看到什麼代表什麼:這些 IP 如果不在 Google/OpenAI/Anthropic 公布的爬蟲網段內,那就是偽裝;同一批 IP 通常也打了別的路徑。
來源
- The Hacker News:Mass-Scanning Campaign Exploits Vite Flaw to Extract Cloud Credentials(2026-09-15)
- GitHub Advisory GHSA-v2wj-q39q-566r:server.fs.deny bypassed with queries
- CVE-2026-39364(cvefeed)
本文為公開報導與官方公告的整理與拆解,非第一手鑑識;證據等級依來源可信度標註。
M2 身分與金鑰 · M7 殭屍網路解剖(掃密工具與 IOC) · 想在自己的環境做一次同樣的盤點,從 自我盤點 開始。
每篇新文章一封:三點摘要、攻擊者/防守者視角、今天能做的一件事。或先 加入會員 記錄你完成的任務。