資安指南

用 gitleaks 在提交前攔下機密:在 push 之前堵住 API 金鑰洩漏

不小心提交了 API 金鑰,它就會留在 Git 歷史裡,等於永久外洩。本文說明 gitleaks 如何用 pre-commit 掛鉤和 CI 兩道檢查攔下機密,以及光靠檢出無法完成、必須另外進行的撤銷步驟。

發布於 2026-06-12 更新於 2026-10-06 閱讀時間 6 分鐘
本頁內容

適用對象:在個人開發或小團隊中使用 Git,擔心「會不會不小心把 API 金鑰提交上去」的人。這裡不講攻擊者的手法,只講阻止機密從自己的儲存庫外洩的機制。

本站的看法:光靠 .gitignore 保護不了機密

「我的 .env 已經寫進 .gitignore,所以沒問題」是常見的說法,但它有漏洞。.gitignore 只能讓新檔案不被追蹤,抓不到已經提交的機密、匆忙中用 git add -f 強制加入的檔案,或像 .env.local.bak 這樣意想不到的檔名。它只能擋住機密混入的部分途徑。你需要的是實際檢查提交內容、標出「看起來像機密的字串」的檢測工具。這就是 gitleaks 的用途。

為什麼要在「提交前」攔下

機密之所以危險,是因為 Git 會永久保留歷史。從最新的檔案刪除,它仍留在過去的提交中。而且一旦 push,那段歷史就會被複製到其他電腦、伺服器和 CI 記錄。

留在歷史
最新版已刪除,過去的提交仍有
push=擴散
被複製到其他電腦、伺服器、CI 記錄
必須撤銷
外洩過的金鑰只能重新簽發
兩道檢查
在 pre-commit 和 CI 攔下

所以機密防護的重點其實是外洩前的預防,而不是外洩後的補救。這和「不要把機密留在公開目錄」的盤點(→ 公開目錄的盤點)是同樣的想法,只是套用到程式碼上。

在哪些階段檢出機密

在機密從程式碼流向外界的路徑上,可以設置兩道檢查:本機提交的當下,以及分享出去之前(CI)。

程式碼中的機密

API 金鑰、私鑰、token

→

檢查 1:pre-commit

提交時在本機檢出並中止

→

檢查 2:CI / cron

push 後、合併/部署前檢出

→

公開/分享

到了這裡,就當作已外洩

外洩路徑與兩道檢查。pre-commit 在本機攔下;CI 在合併/部署前攔下。

如何導入 gitleaks

1

先掃描既有的歷史

導入時,先用 gitleaks git(v8.19.0 之前的版本為 gitleaks detect)掃描整個儲存庫歷史一次。找出留在過去提交中的機密是第一項工作。在這裡找到的任何東西,如下所述,都要假設需要撤銷。
2

用 pre-commit 掛鉤加上檢查 1

每次提交時執行 gitleaks git --pre-commit --staged(舊為 gitleaks protect --staged),讓含有機密的提交當場中止。把它加入 pre-commit 框架(.pre-commit-config.yaml),讓每個人在本機都套用相同的檢查。
3

在 CI / cron 加上檢查 2

掛鉤可以被每個人自行停用,所以要在分享出去之前再檢查一次。把 gitleaks git 作為 CI 工作執行,自架環境則作為定期掃描,抓住漏網之魚(和相依套件稽核相同的自動監控思維)。
4

在 .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 gitGit 提交歷史第一次的完整歷史掃描、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 release

GitHub 上的 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 protectionpush 到 GitHub 時GitHub 支援的機密類型可以提供理由略過。對其他 Git 伺服器沒有作用

GitHub 針對使用者的 push protection 在推送到公開儲存庫時預設開啟。它是免費的安全網,但不會攔下本機提交,不支援格式的金鑰或手動組合的連線字串也可能通過(詳見 為什麼在 GitHub 上曝光的憑證仍然有效,英文)。gitleaks 涵蓋的是它之前的步驟,以及 GitHub 以外的所有地方。

如何檢查自己的環境

設定過一次不代表它正在運作。在你自己的儲存庫中,依序確認以下事項。

1

確認 gitleaks 的版本

執行 gitleaks version。早於 v8.19.0 的版本沒有 gitleaks git 等新指令,請更新。

2

確認掛鉤已登記

確認 .git/hooks/pre-commit 是否存在。如果 git config --get core.hooksPath 指向其他資料夾,就去那裡確認。Git 在 clone 時不會複製掛鉤,所以在新電腦或新的 clone 上要再執行一次 pre-commit install。

3

掃描整個歷史一次

在儲存庫根目錄執行 gitleaks git --redact -v。沒有檢出時結束碼為 0。如果找到了,用輸出中的檔名和提交,到簽發者的管理主控台確認那把金鑰是否仍然有效。

4

也掃描 Git 以外的資料夾

伺服器上的公開資料夾、備份,以及你發布的 zip 內容,在 Git 歷史掃描中都看不到。用 gitleaks dir (path to folder) --redact 檢查(→ 公開目錄的盤點)。

5

確認 .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 檔與機密和安全保存密碼相同。

接下來閱讀

出處

  • 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

FAQ

Qgitleaks 是什麼?
A

一款免費工具,會掃描 Git 儲存庫的工作樹和提交歷史,檢出 API 金鑰、私鑰、token 等機密是否被提交。它用正規表示式規則和字串的熵(隨機程度)找出「看起來像機密的字串」,可以作為 pre-commit 掛鉤或在 CI 中執行自動檢查。

Q寫進 .gitignore 不就能保護機密了嗎?
A

不夠。.gitignore 只能阻止「新的追蹤」,無法檢出已經提交的機密,也擋不住用 git add -f 強制加入的檔案。它只能防止部分事故,所以要在 pre-commit 和 CI 都搭配 gitleaks 這類檢測工具。

Q不小心把機密提交並 push 了怎麼辦?
A

把那個機密當作已外洩。最優先的不是改寫歷史,而是撤銷並輪換(重新簽發)外洩的金鑰或 token。進入公開儲存庫或記錄的機密要假設已無法收回:先讓它失效,再清理歷史並加上預防措施(gitleaks)。

Qgitleaks detect 和 gitleaks protect 還能用嗎?
A

還能執行,但在 v8.19.0 已被標為棄用,也不會出現在說明輸出中。現行的指令是 gitleaks git(掃描提交歷史)、gitleaks dir(掃描資料夾和檔案)和 gitleaks stdin(掃描透過管線傳入的內容)。pre-commit 檢查現在是 gitleaks git --pre-commit --staged,官方的 pre-commit 掛鉤執行的也是這個指令。設定時請使用新指令。

Q如果已開啟 GitHub 的 push protection,還需要 gitleaks 嗎?
A

兩者涵蓋的範圍不同,所以兩個都用。GitHub 針對使用者的 push protection 在推送到公開儲存庫時預設開啟,但可以選擇理由略過,而且對本機提交和 GitHub 以外的 Git 伺服器沒有作用。gitleaks 在提交之前就在你的電腦上攔下機密,也能在自架 Git 伺服器或任何 CI 上執行相同的規則。

Q如何讓 gitleaks 不再標記測試用的假金鑰?
A

有三種方法:在那一行加上 gitleaks:allow 註解、把檢出結果的指紋放進 .gitleaksignore,或在 .gitleaks.toml 的 allowlist 中排除檔案或模式。無論用哪一種,都要留下註解說明為什麼它是安全的。最該避免的失敗,是把真正的金鑰當作誤報加入 allowlist。