適用對象:在個人開發或小團隊中使用 Git,擔心「會不會不小心把 API 金鑰提交上去」的人。這裡不講攻擊者的手法,只講阻止機密從自己的儲存庫外洩的機制。
本站的看法:光靠 .gitignore 保護不了機密
「我的 .env 已經寫進 .gitignore,所以沒問題」是常見的說法,但它有漏洞。.gitignore 只能讓新檔案不被追蹤,抓不到已經提交的機密、匆忙中用 git add -f 強制加入的檔案,或像 .env.local.bak 這樣意想不到的檔名。它只能擋住機密混入的部分途徑。你需要的是實際檢查提交內容、標出「看起來像機密的字串」的檢測工具。這就是 gitleaks 的用途。
為什麼要在「提交前」攔下
機密之所以危險,是因為 Git 會永久保留歷史。從最新的檔案刪除,它仍留在過去的提交中。而且一旦 push,那段歷史就會被複製到其他電腦、伺服器和 CI 記錄。
所以機密防護的重點其實是外洩前的預防,而不是外洩後的補救。這和「不要把機密留在公開目錄」的盤點(→ 公開目錄的盤點)是同樣的想法,只是套用到程式碼上。
在哪些階段檢出機密
在機密從程式碼流向外界的路徑上,可以設置兩道檢查:本機提交的當下,以及分享出去之前(CI)。
程式碼中的機密
API 金鑰、私鑰、token
檢查 1:pre-commit
提交時在本機檢出並中止
檢查 2:CI / cron
push 後、合併/部署前檢出
公開/分享
到了這裡,就當作已外洩
如何導入 gitleaks
先掃描既有的歷史
gitleaks git(v8.19.0 之前的版本為 gitleaks detect)掃描整個儲存庫歷史一次。找出留在過去提交中的機密是第一項工作。在這裡找到的任何東西,如下所述,都要假設需要撤銷。用 pre-commit 掛鉤加上檢查 1
gitleaks git --pre-commit --staged(舊為 gitleaks protect --staged),讓含有機密的提交當場中止。把它加入 pre-commit 框架(.pre-commit-config.yaml),讓每個人在本機都套用相同的檢查。在 CI / cron 加上檢查 2
gitleaks git 作為 CI 工作執行,自架環境則作為定期掃描,抓住漏網之魚(和相依套件稽核相同的自動監控思維)。在 .gitleaks.toml 調整誤報
.gitleaks.toml 調整規則和 allowlist。正確做法不是「把警告關掉」,而是「記錄它為什麼安全」。沒有理由的排除,可能成為下一次事故的原因。檢出時,先「撤銷」,改寫歷史在後
發現已提交並 push 的機密時,最優先的是撤銷並重新簽發(輪換)那個金鑰或 token。用 git filter-repo 從歷史中刪除很重要,但那只是「防止進一步擴散」的清理。進入公開儲存庫、fork、CI 記錄或別人 clone 的機密,要假設已無法收回:先讓它失效,再清理歷史。順序顛倒的話,你還在刪除的時候它就可能被拿去使用。
依賴 .gitignore
- 只能防止新的追蹤
- 已經提交的機密不會被檢出
- 對
git add -f或奇怪的檔名無能為力 - 無法確認「我沒打算加入那個檔案」
gitleaks(檢出+撤銷的做法)
- 實際檢查工作樹和歷史的內容
- 用 pre-commit 和 CI 兩道檢查攔下
- 檢出時,有一套一路做到撤銷的流程
- 誤報在記錄理由後才排除
該用哪個指令(v8.19.0 以後)
gitleaks 在 v8.19.0 重新整理了指令。舊的 detect 和 protect 仍可執行,但已棄用,也不再出現在說明中。新的設定請使用以下指令:
| 指令 | 掃描對象 | 典型用途 |
|---|---|---|
gitleaks git | Git 提交歷史 | 第一次的完整歷史掃描、CI、定期掃描 |
gitleaks git --pre-commit --staged | 即將提交的變更(已暫存) | pre-commit 掛鉤(官方掛鉤執行的正是這個指令) |
gitleaks dir | 資料夾和檔案,包括不在 Git 中的 | 公開網頁資料夾、備份、解壓後的發布 zip |
gitleaks stdin | 從標準輸入透過管線傳入的文字 | 其他指令的輸出或記錄 |
gitleaks 找到至少一筆外洩時以結束碼 1 結束,沒有找到時為 0,所以 CI 和 cron 工作可以依結束碼判定失敗。加上 --redact,機密本身就不會出現在輸出或記錄中。
設定範例:pre-commit 掛鉤與 GitHub Actions
使用 pre-commit 框架時,把這個檔案放在儲存庫根目錄。加入時把 rev 設為最新版本(截至 2026 年 10 月為 v8.30.1)。
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1
hooks:
- id: gitleaks除了 gitleaks(以 Go 建置)之外,id 也可以是 gitleaks-docker(在 Docker 中執行)或 gitleaks-system(使用電腦上已安裝的 gitleaks)。接著每個人在自己的電腦上執行:
pip install pre-commit # install pre-commit itself
pre-commit install # register the hook in this repo (once per clone)
pre-commit run --all-files # check every file once, right after registering
pre-commit autoupdate # run now and then to move rev to a newer releaseGitHub 上的 CI 有官方的 GitHub Action。它需要完整的歷史,所以用 fetch-depth: 0 進行 checkout。
# .github/workflows/gitleaks.yml
name: gitleaks
on:
pull_request:
push:
schedule:
- cron: "0 4 * * *"
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}組織帳號擁有的儲存庫,這個 Action 需要授權金鑰(GITLEAKS_LICENSE)。官方 README 表示,這個金鑰可以從 gitleaks.io 免費取得,個人帳號則不需要。在自架 Git 伺服器或 GitHub 以外的 CI 上,在工作中執行 gitleaks git --redact 也能達到相同效果。
在哪裡檢查:四個位置的比較
任何單一檢查都有漏洞。把每一個能攔下什麼、會在哪裡漏掉排列出來,就能看出為什麼要組合使用。
| 位置 | 攔下的時間點 | 涵蓋範圍 | 漏洞與限制 |
|---|---|---|---|
| pre-commit 掛鉤(本機) | 提交之前 | 已暫存的變更 | 可用 git commit --no-verify 或 SKIP=gitleaks 略過。clone 儲存庫不會安裝掛鉤 |
| CI(GitHub Actions 等) | 合併或部署之前 | 已 push 的提交和歷史 | push 已經發生。公開儲存庫的話,就當作已外洩 |
| 定期掃描(cron) | 事後發現 | 整個儲存庫歷史 | 發現前有延遲。能用新規則抓到舊提交中的機密 |
| GitHub push protection | push 到 GitHub 時 | GitHub 支援的機密類型 | 可以提供理由略過。對其他 Git 伺服器沒有作用 |
GitHub 針對使用者的 push protection 在推送到公開儲存庫時預設開啟。它是免費的安全網,但不會攔下本機提交,不支援格式的金鑰或手動組合的連線字串也可能通過(詳見 為什麼在 GitHub 上曝光的憑證仍然有效,英文)。gitleaks 涵蓋的是它之前的步驟,以及 GitHub 以外的所有地方。
如何檢查自己的環境
設定過一次不代表它正在運作。在你自己的儲存庫中,依序確認以下事項。
確認 gitleaks 的版本
執行 gitleaks version。早於 v8.19.0 的版本沒有 gitleaks git 等新指令,請更新。
確認掛鉤已登記
確認 .git/hooks/pre-commit 是否存在。如果 git config --get core.hooksPath 指向其他資料夾,就去那裡確認。Git 在 clone 時不會複製掛鉤,所以在新電腦或新的 clone 上要再執行一次 pre-commit install。
掃描整個歷史一次
在儲存庫根目錄執行 gitleaks git --redact -v。沒有檢出時結束碼為 0。如果找到了,用輸出中的檔名和提交,到簽發者的管理主控台確認那把金鑰是否仍然有效。
也掃描 Git 以外的資料夾
伺服器上的公開資料夾、備份,以及你發布的 zip 內容,在 Git 歷史掃描中都看不到。用 gitleaks dir (path to folder) --redact 檢查(→ 公開目錄的盤點)。
確認 .env 是否曾被提交
執行 git log --all --oneline -- .env,看看過去是否有任何提交動過 .env。只要出現一行,那個時間點的內容就在歷史裡。
處理誤報
測試用的假金鑰和文件中的範例常常被標記。排除方法有三種;請使用可行範圍內最窄的那一種。
- 以行為單位:在那一行加上
gitleaks:allow註解 - 以檢出結果為單位:把輸出中顯示的指紋加入儲存庫根目錄的
.gitleaksignore(README 將此標為實驗性功能) - 以檔案或模式為單位:加入
.gitleaks.toml的 allowlist
如果自己撰寫 .gitleaks.toml,在 [extend] 底下加上 useDefault = true 以保留預設規則。只有自訂規則的設定檔,會默默漏掉預設規則本來能抓到的金鑰。
如果舊儲存庫已有大量檢出結果,把過去的報告傳給 --baseline-path,就只會回報新的檢出結果。不過,請先撤銷報告中的金鑰。把金鑰放進 baseline,並不會讓它變安全。
常見錯誤與修正
- 以為有設定檔就夠了:在有人執行
pre-commit install之前,掛鉤不會做任何事。請每個人都執行,並在 CI 中執行相同的檢查作為第二層。 - 習慣了
--no-verify:把 CI 檢查設為合併的必要條件,這樣即使略過掛鉤也能被抓到。 - 把機密印到 CI 記錄中:加上
--redact。CI 記錄也有很多人能看到。 - 在 CI 中掃描淺層 clone:只會檢查最新的提交,歷史中的機密會被漏掉。設定
fetch-depth: 0。 - 從歷史刪除後就停下:GitHub 自己的指南把撤銷或輪換機密列為第一步。fork、clone 和快取中的副本無法刪除。
- 把真正的金鑰當作「誤報」加入 allowlist:在註解中寫下理由,並在審查時確認。
實際案例:存取金鑰被公開
2022 年 10 月 7 日,豐田汽車(Toyota Motor Corporation)宣布,其連網汽車服務 T-Connect 使用者網站的部分原始碼曾在 GitHub 上公開。根據該公司的公告:
- 2017 年 12 月,負責開發該網站的委外廠商誤將部分原始碼上傳到設為公開的 GitHub 帳號
- 程式碼中包含存放客戶資訊的資料伺服器存取金鑰
- 程式碼在 2022 年 9 月 15 日改為非公開,存取金鑰在 9 月 17 日更換
- 受影響的是 296,019 筆電子郵件地址和客戶管理編號。存取記錄中沒有發現第三方使用,但該公司表示無法完全排除
從上傳到移除大約經過了五年。而且它發生在公司自己的儲存庫之外,也就是委外廠商的帳號中。對自己儲存庫的掃描,無法觸及你的程式碼最終流向的每個地方,所以也要限制每把金鑰能做的事,並定期輪換金鑰。即使在這個案例中,金鑰也是在程式碼下架兩天後才更換:找到之後,就要更換金鑰。
私有儲存庫也不是存放機密的安全地方。在 CAMPFIRE 2026 年的案例中,據該公司表示,遭濫用的 GitHub 憑證是起點,在 GitHub 上可以看到的資訊被用來取得雲端憑證(→ CAMPFIRE 外洩事件,英文)。私有儲存庫也不要放機密,並且用 gitleaks 定期掃描。
本站是怎麼做的
本站的基本規則是機密完全不放進 Git:連線字串和 API 金鑰只放在伺服器上受保護的設定中(權限受限的 env 檔),既不以明文放在儲存庫裡,也不放在交接筆記中(→ 不把機密放進 git/自架 Git vs GitHub)。在此之上,再以人一定會出錯為前提,疊加檢測工具。設計保證「不放進去」,gitleaks 這類掃描則抓住「還是放進去了」的情況,這兩層就是本站防止機密外洩的做法。處理機密的原則本身,與 .env 檔與機密和安全保存密碼相同。
接下來閱讀
- GitHub 設定:如何設定 GitHub 雙重驗證
- 基礎:.env 檔和 API 金鑰:會出什麼問題、如何保護
- 從 GitHub 憑證到外洩:CAMPFIRE 外洩事件(2026)(英文)
- 外洩之後:在 GitHub 上曝光的 543,699 筆憑證仍然有效:為什麼必須撤銷,而不只是刪除(英文)
- 攻擊在無人操作下進行時:Hugging Face 入侵事件,以及防守方必須放棄的假設
- 盤點:有沒有把機密留在公開目錄裡
- 自架:不把機密放進 git/自架 Git vs GitHub
- 術語:什麼是「.env」:環境變數檔外洩會發生什麼
- 工具:機密外洩檢查工具(貼上檢查)
出處
- gitleaks(官方儲存庫)README:指令(git、dir、stdin)、v8.19.0 中 detect/protect 的棄用、結束碼、
--redact、gitleaks:allow、.gitleaksignore、--baseline-path、設定的擴充 — github.com/gitleaks/gitleaks / 官方掛鉤定義 — .pre-commit-hooks.yaml / Releases - gitleaks-action(官方 GitHub Action)README:工作流程範例與授權金鑰 — github.com/gitleaks/gitleaks-action
- pre-commit 文件(install、run --all-files、autoupdate、SKIP)— pre-commit.com
- Git 文件「githooks」(pre-commit 掛鉤與 --no-verify)— git-scm.com
- GitHub Docs「About push protection」— docs.github.com / 「Removing sensitive data from a repository」— docs.github.com
- 豐田汽車,關於客戶電子郵件地址可能外洩的公告(2022 年 10 月 7 日,日文)— global.toyota