.env 跟著 repo
一起上了 GitHub

速讀:5 分鐘掌握重點

為什麼現在很紅:兩年前某個 commit 裡的一把雲端金鑰,後來的版本早就刪了;repo 一改成公開,它就跟著 git 歷史一起被看見。

一句話結論
金鑰先寫進 .env 或程式碼「等一下再改」,某次 commit 就把它帶進 git 歷史;在最新版本刪掉,不等於消失。
他要的是什麼
他不用入侵你的伺服器。等你把 repo 改成公開,翻一下 git 歷史,兩年前那把金鑰還在原地。
你今天做一件事
今天就對最重要的 repo 跑一次完整歷史掃描,並確認 secret scanning 和 push protection 都開了。 直接去做 →
哪些能信
3 可證明2 推論2 缺口 每個主張都標了等級,缺口是誠實寫出來的。
破口速查
受害端一律去識別化;寫「未公開」代表公開資料查不到。
伺服器服務商
不適用(示意情境;涉及的是程式碼平台上的 repo 與雲端帳號)
網路服務商
不適用(同上)
漏洞出現的地方
程式碼層:金鑰寫在 .env 或程式碼常數裡被 commit,之後雖在最新版本刪除,但仍留在 git 歷史;repo 從私有改成公開,或被外包、離職者、遭入侵的帳號看到,金鑰就外洩
馬上自我檢測
git log --all --oneline -- .env gitleaks git --redact . git check-ignore -v .env 程式碼平台的 repo 設定 → 安全性頁,確認 secret scanning 與 push protection 是否已開啟
漏洞修補方式
外洩時先到服務商後台撤銷或輪換金鑰,再清理 git;對所有 repo 跑完整歷史掃描;開啟 secret scanning 與 push protection,本機加 pre-commit hook;每個專案放 .env.example 並把 .env 列進 .gitignore;金鑰移到密鑰管理服務或部署平台環境變數;改公開前一律掃描完整歷史
有 15 分鐘再看:其餘 2 點
  1. repo 一改公開就可能被持續掃描;私有 repo 也不保險,外包、離職者、遭入侵的帳號都看得到。
  2. 外洩時先撤銷再清理;平時用 GitHub secret scanning、push protection 和 Gitleaks、TruffleHog 這類開源掃描器找出與擋下,再把金鑰移出程式碼。

「先寫死,等一下再改。」資料庫密碼、API key、雲端金鑰先放進 .env 或程式碼裡,某天 .gitignore 少一行、或 repo 從私有改成公開,金鑰就跟著程式碼一起出去了。在最新版本刪掉,git 歷史還記得。

作者分析:金鑰留在 git 歷史,repo 改公開後被濫用(示意情境,非真實事件)·示意情境:舊專案 repo 改成公開,幾天後雲端帳單出現異常·全文 7 分鐘
本篇目錄

為了展示作品,把舊 repo 改成公開

假設有一家十人的 App 開發工作室,為了展示作品,把一個舊專案的 repo 從私有改成公開。幾天後雲端帳單出現異常,有人用他們的金鑰開了大量運算資源。追查發現,金鑰在兩年前的某個 commit 裡;後來的版本雖然刪掉了,但 git 歷史還留著。

先說清楚,這是示意情境,不是真實事件,工作室與經過都是為了說明而設。但「先寫死,等一下再改」幾乎每個工程師都說過:資料庫密碼、第三方 API key、雲端金鑰,先放進 .env 或直接寫在程式碼裡,功能跑起來最重要。然後某天 .gitignore 少了一行,或是有人把 repo 改成公開。

這篇要講的只有一件事:金鑰一旦進了 git,就要當它已經出去了。

git 會記住一切

第一層是歷史。在最新版本刪掉,不等於消失;任何一個舊 commit 都還能把它翻出來。

第二層是公開。公開 repo 會被持續掃描,金鑰一公開,就可能很快被找到並濫用。

第三層是私有也不保險。外包、離職者、被入侵的帳號,都能看到私有 repo 的完整歷史。

最後是擴散。一把金鑰往往用在很多地方,外洩後要找出所有用到它的位置,才能安全撤換;找不齊,就只能邊換邊等哪裡壞掉。

這篇示意情境裡,跟著 repo 出去的是什麼

這是示意情境,沒有實際外洩;下表列的是這類事件裡最常跟著 repo 一起出去的憑證,讓你知道一個 .env 裡可能放了幾把鑰匙。

leaked credentials這次外洩了什麼:服務、用途、存在形式
服務憑證類型用途存在形式放在哪權限範圍狀態
雲端帳號(IAM)長期存取金鑰讓程式部署與操作雲端資源明文寫在 .env 或程式碼常數裡兩年前的某個 commit;最新版本已刪,git 歷史仍在至少能建立運算資源(示意情境中被拿來開大量運算資源)示意情境;撤銷前持續有效
同一個 .env 裡的其他密鑰(資料庫密碼、第三方 API key)密碼/API key連資料庫、呼叫第三方服務明文環境變數同一個 commit 的可能性高,但未逐一確認依各服務而定是否一起外洩無法確認
憑證本身已遮蔽或失效;這裡只說明它是哪個服務、拿來做什麼、以什麼形式存放,讓你能對照自己的環境。

第二列標成缺口,是因為「同一個檔案裡的其他鑰匙有沒有也被拿走」,在示意情境裡沒有人查過。

能證明的、只能推論的

這篇是觀點文,情境是示意的,所以能證明的只有官方文件與官方公告寫明的事;情境裡的經過只能算推論,不知道的就寫成缺口。

不花錢就能做的流程

到這裡,其實已經足夠理解問題在哪。如果你想直接動手,可以跳到「今天就可以來試試」;下面是完整的六步流程。

第一步,外洩時,先撤銷再清理。 第一步是到服務商後台撤銷或輪換金鑰,而不是先改 git 歷史。改寫歷史無法收回已經被複製的內容。

第二步,掃一次所有 repo。 GitHub 的 secret scanning 會掃描所有分支的完整歷史;開源的 Gitleaks(git、dir 指令可以掃 repo 和本機目錄)、TruffleHog(README 說可以找出、驗證並分析外洩憑證)也能自己跑。

第三步,在推送前擋下來。 開啟 GitHub 的 push protection;本機也可以用 pre-commit hook 搭配開源掃描器。

第四步,標準化 .gitignore 和範本。 每個專案都放 .env.example,只有欄位名稱,沒有值;.env 一律列進 .gitignore。範本長這樣:

# .env.example:只放欄位名稱,值留空
DATABASE_URL=
PAYMENT_API_KEY=
CLOUD_ACCESS_KEY_ID=
CLOUD_SECRET_ACCESS_KEY=

第五步,金鑰移出程式碼。 正式環境改從密鑰管理服務或部署平台的環境變數讀取。

第六步,公開 repo 前做檢查。 把「掃描完整歷史」列為改成公開前的必要步驟,寫進一張 go-public-checklist-g5,沒勾完不改公開。

什麼時候不需要買工具

GitHub 平台內建功能加上開源掃描器,已經涵蓋「找出」和「擋下」兩件事。密鑰管理平台的價值在於「金鑰從哪裡來」,適合有多個環境和多人協作的團隊。

市面上大致分五類。程式碼平台內建:GitHub secret scanning 和 push protection(私有 repo 的可用性依方案而定)。開源掃描器:Gitleaks、TruffleHog。雲端原生密鑰管理:AWS Secrets Manager、Google Cloud Secret Manager。開源密鑰管理:Infisical(GitHub 上開源)、OpenBao(Linux 基金會 OpenSSF 下的開源 Vault 分支,MPL-2.0 授權)。商用密鑰管理:例如 HashiCorp Vault(現為 IBM 旗下,授權已改為 BSL)、1Password 的開發者密鑰管理(官網說可以在程式碼裡用引用取代金鑰本身,並有 GitHub Actions 等 CI/CD 整合)。

限制也要一起看:掃描器有誤判也有漏判,自訂格式的密鑰可能偵測不到;密鑰管理平台要改程式的讀取方式,導入有成本。選的時候問三件事:程式碼放在哪(在 GitHub 的話,先開內建功能)、基礎架構是不是主要在單一雲端(是的話,雲端原生的密鑰管理最省事)、有沒有自架能力(OpenBao 這類自架方案需要維運能力)。

後續更新兩則。2026/07/28,1Password 宣布 1Password Environments 正式提供,用於管理和共享專案的環境變數設定。2026/10/17 查證時,Gitleaks 的 README 寫明專案已「功能完整」,之後只發布安全修補,作者轉而開發 Betterleaks;既有用法仍可使用,長期導入時請把維護狀態納入考量。

這篇提到的項目要花多少錢

來源沒有列異常帳單金額與商用方案價格,表裡照實標成未公開或估算。

cost金鑰跟著 repo 出去的成本
項目用量單價期間US$NT$舉證
示意情境中被開出的大量運算資源未公開未公開repo 公開後數天——示意情境,無實際帳單
對所有 repo 跑一次完整歷史掃描
估
工程師一人估 2–4 小時一次性——本站依流程估算,依 repo 數量而定
Gitleaks/TruffleHog開源軟體免費—0.000各專案 GitHub 頁
GitHub secret scanning(私有 repo)依方案可用性與費用依方案———官方文件註明依方案而定,本文未取得價格
攻擊者撿到公開 repo 裡的金鑰
估
翻 git 歷史幾乎零成本———本站推估;無攻擊端資料
合計(僅可證明列)0.000
匯率假設 1 USD ≈ NT$32。單價為公開牌價或帳單實付,來源:本站估算;GitHub Docs、各開源專案頁(2026-10-17 讀取)。「舉證」欄標明每筆損失的證據來源與等級( 可證明 推論 缺口)。

攻擊者那一列幾乎是零,防守那一列卻是一整個晚上的撤換與追查;這就是為什麼要在推送前擋下來。

你可以學到什麼

站在攻擊者那一側看,公開 repo 的 git 歷史是一個不會過期的寶箱。他不用猜密碼,也不用打穿任何系統,只要在你改成公開的那幾天之內翻到那個舊 commit。歷史不替任何人守密。

lessons本案的 5 個教訓
  1. 01
    金鑰在最新版本刪掉不等於消失,git 歷史裡的每個舊 commit 都還能把它翻出來。
  2. 02
    外洩時先到服務商後台撤銷或輪換金鑰,再清理 git;改寫歷史收不回已經被複製的內容。
  3. 03
    GitHub secret scanning 會掃所有分支的完整歷史,push protection 能在推送前擋下可辨識的密鑰,兩者都該先打開。
  4. 04
    每個專案放只有欄位名稱的 .env.example,並把 .env 列進 .gitignore,讓「先寫死」沒有機會被 commit。
  5. 05
    repo 改成公開前,一律先掃描完整歷史;這一步做了,示意情境裡的那筆帳單就不會出現。
keywords重點學習:最需要學習的 10 個關鍵字10 個
  1. 01
    .env
    這篇的主角:最常放明文金鑰、也最常被誤 commit 的檔案。
  2. 02
    git 歷史
    刪掉的檔案還在舊 commit 裡,掃描與清理都要看完整歷史。
  3. 03
    Secret Scanning
    GitHub 內建的完整歷史掃描,先開它就能找出多數已知格式的密鑰。
  4. 04
    Push Protection
    在推送前擋下密鑰,比外洩後補救便宜得多。
  5. 05
    .gitignore
    少一行就會把 .env 帶進 repo,是最小也最常見的破口。
  6. 06
    .env.example
    只有欄位名稱的範本,讓新成員知道要設什麼,又不會帶出值。
  7. 07
    Gitleaks
    可以自己跑的開源掃描器,git 與 dir 指令分別掃 repo 和本機目錄;注意目前只發布安全修補。
  8. 08
    TruffleHog
    開源掃描器,能找出並驗證外洩憑證是否仍有效。
  9. 09
    pre-commit hook
    在本機 commit 前就攔下,補上平台功能管不到的那一段。
  10. 10
    密鑰管理(Secrets Manager)
    把金鑰移出程式碼的去處,回答「金鑰從哪裡來」。
try today今天就可以來試試約 15 分鐘

全部唯讀,不改任何設定;做完你會知道自己有沒有同樣的破口。

  1. 在最重要的 repo 裡,列出歷史上所有動過 .env 的 commit(唯讀)
    git log --all --oneline -- .env
    看到什麼代表什麼:有任何輸出,代表 .env 曾經被 commit 過,裡面的金鑰要當作已外洩處理。
  2. 確認 .env 有被 .gitignore 忽略(唯讀)
    git check-ignore -v .env
    看到什麼代表什麼:印出是哪個 .gitignore 的哪一行在忽略它;沒有輸出就代表沒被忽略。
  3. 已安裝 Gitleaks 的話,掃一次 repo 的完整歷史,結果遮蔽顯示(唯讀)
    gitleaks git --redact .
    看到什麼代表什麼:列出的每一筆都要到服務商後台確認是否仍有效;沒有發現也不代表沒有,掃描器會漏判。
  4. 打開程式碼平台該 repo 的設定 → 安全性頁,看 secret scanning 與 push protection 的狀態(唯讀,不要改)
    看到什麼代表什麼:顯示未開啟的,就是今天可以先打開的兩個開關。
  5. 列出公司所有公開 repo,標出哪些是從私有改成公開的(不用指令)
    看到什麼代表什麼:改過公開的 repo,都要確認改之前有沒有掃過完整歷史。

揭露:本文未受任何廠商贊助,提及的產品僅為舉例。

想看全部細節?

環境背景、時間線、攻擊鏈對照 ATT&CK、關鍵證據、根因、處置與檢討都在完整版,約 7 分鐘。

來源

本文為公開報導與官方公告的整理與拆解,非第一手鑑識;證據等級依來源可信度標註。

本文由 AI 團隊協助研究與撰寫,經隱私與事實檢查後發布;證據等級依來源可信度標註。

看完的心情
ai prompt把這篇的切入點帶回你的環境

複製下面這段,貼給你在用的 AI 工具(Claude Code、Cursor、Copilot、ChatGPT 都可以)。它會用本篇的破口位置、自我檢測與學習重點,對你的專案或環境做一次資安掃描,列出潛在問題與建議的調整或加強方式。

預設是唯讀:只發現問題、提出建議,不會改你任何檔案或設定。

§
對應課程模組

M2 身分與金鑰 · 想在自己的環境做一次同樣的盤點,從 自我盤點 開始。

newsletter
下一篇拆解直接寄到信箱

每篇新文章一封:三點摘要、關鍵字定義、今天能做的一件事。或先 加入會員 記錄你完成的任務。