在 git commit 之前自動攔截並防範 API 金鑰與密鑰外洩。
LeakBolt 幫你在 git commit 之前擋下不小心寫進程式碼的 API 金鑰與密鑰。裝一次,這台機器上所有 repo(包含之後新建的)都受保護——除非某個 repo 用了 husky/lefthook 這類 hook 工具,它們會接管 hook 設定;那種 repo 執行一次 leakbolt install 就能讓兩者共存(詳見與其他 hook 工具共存)。
它不自己做偵測——偵測引擎用的是 gitleaks。LeakBolt 做的是 gitleaks 沒做的那一層:一個安裝檔裝好全部(含 gitleaks)、一次設定保護所有 repo、檢查 hook 有沒有失效、擋下時跳原生視窗說明、處理誤報、把誤加進版控的憑證檔移出去。
全部在本機執行。 不需要註冊帳號、不需要 API 金鑰、沒有掃描次數上限,程式碼不會離開這台電腦,離線也能用。
用 .pkg 安裝的話沒有前置需求,gitleaks v8.30.1 已經包在裡面,裝到 /usr/local/leakbolt/bin/gitleaks,不會覆蓋你自己裝的那份。
自行編譯的話要自己先裝 gitleaks,版本 v8.30.1:
- macOS 安裝方式:
brew install gitleaks - 官方專案頁面:https://github.com/gitleaks/gitleaks
若找不到 gitleaks,執行 leakbolt scan 會回報錯誤並中止:
找不到 gitleaks。請安裝 gitleaks v8.30.1 後重試:https://github.com/gitleaks/gitleaks
版本若不是 8.30.1,每次執行會印出警告,但仍會繼續掃描。
brew install aqua5230/leakbolt/leakbolt
會自動裝好 leakbolt 本體,並透過 depends_on 一併裝好 gitleaks,不會跳 Gatekeeper 警告。裝完後執行 leakbolt install --global 開啟全機保護(Homebrew 版不會自動開啟,需手動執行一次)。
到 Releases 頁面 下載 LeakBolt-<版本>.pkg,內含 leakbolt 與 gitleaks,兩者都是 universal binary,Intel 與 Apple Silicon 共用同一個檔案。也可以自行執行 sh scripts/build_pkg.sh 本機產生。
安裝檔會做三件事:把 leakbolt 放進 /usr/local/bin、把 gitleaks 放進 /usr/local/leakbolt/bin、以目前登入的使用者身分執行 leakbolt install --global 開啟全機保護。
安裝檔目前未經 Apple 簽章與公證,從瀏覽器下載後點兩下會被 Gatekeeper 擋,且 macOS Sequoia(15)起已移除「按右鍵選打開」這條捷徑,只剩「系統設定」這條路:點兩下讓它被擋 → 開啟「系統設定 → 隱私權與安全性」→ 捲到「安全性」區塊 → 按被擋項目旁的「仍要打開」→ 在重新跳出的警告按「打開」並輸入管理者密碼。
這幾步對不常開終端機的人相當勸退,所以目前建議優先走 Homebrew。簽章需要 Apple Developer Program 帳號(年費 US$99,公證不另外收費也不需要硬體金鑰);scripts/build_pkg.sh 已預留 LEAKBOLT_SIGN_IDENTITY 環境變數,設了才會簽。
解除安裝:sudo sh /usr/local/leakbolt/uninstall.sh。
需要 Go 1.21 或更新版本,執行 cd prototype && go build -o leakbolt .,然後將 leakbolt 放進 PATH。也可以到 Releases 頁面 直接下載對應平台的預編譯執行檔。
若執行檔或安裝檔是從瀏覽器下載或他人傳送,macOS 會因為缺乏 Apple 簽章而阻擋執行,顯示「Apple 無法驗證…是否為惡意軟體」。用 curl 下載則不會被貼隔離標記,不會出現此警告。解法二選一:
- 至「系統設定 → 隱私權與安全性」,捲到「安全性」區塊點擊「仍要打開」(macOS Sequoia 起這是唯一的圖形介面途徑,舊版的「按右鍵選打開」已被 Apple 移除)
- 於終端機執行:
xattr -d com.apple.quarantine <檔案路徑>移除隔離標記
自行用 go build 編譯的執行檔不會遇到此問題。
用 .pkg 安裝的話,裝完就生效,這台機器上所有 repo(包含之後新建的)都受保護,不必再做任何事。
自行編譯的話,執行一次 leakbolt install --global 開啟全機保護;若只想保護單一 repo,在該 repo 根目錄執行 leakbolt install。
驗證是否生效:新增一個包含假金鑰的檔案並加入暫存區,執行 git commit。commit 會被攔截中斷,終端機顯示偵測到的金鑰警告,macOS 上同時跳出提示視窗。
用法:
leakbolt install [--local-only | --global]
leakbolt uninstall --global
leakbolt scan --staged
leakbolt scan --history
leakbolt allow <指紋前綴>
leakbolt guide <指紋前綴>
leakbolt purge-backups
leakbolt untrack <檔案路徑>
leakbolt doctor
版本查詢指令:支援 leakbolt --version、leakbolt -v、leakbolt version,輸出格式如 leakbolt 0.1.0 (3ba8f46),鎖定 gitleaks 8.30.1。
install:在目前 repo 裝上 pre-commit hook,並強制跑一次完整 git 歷史掃描把結果印出來。歷史掃描找到東西時不會讓install回傳非 0——hook 已經裝好了,那些命中是資訊,不是安裝失敗。要取得歷史掃描本身的 exit code 請用leakbolt scan --history。install --global:設定core.hooksPath指向~/.leakbolt/hooks,一次保護這台機器上所有 repo。全域 hook 會先執行該 repo 自己的.git/hooks/pre-commit(若存在且可執行)並傳遞其 exit code,再跑 LeakBolt 檢查,不會靜默停掉既有 hook。若 globalcore.hooksPath已被其他工具佔用,會拒絕安裝而不覆寫。用了 husky/lefthook 的 repo 會蓋過這個設定,見與其他 hook 工具共存。uninstall --global:解除全域保護。只在 globalcore.hooksPath確實指向 LeakBolt 時才解除,指向他人設定則拒絕並保留原值。scan --staged:掃暫存區(staged,指已git add但還沒 commit 的內容)。scan --history:掃完整 git 歷史。allow <指紋前綴>:把某一筆標成誤報並記住,之後不再擋。指紋前綴至少 8 個字元。guide <指紋前綴>:認出是哪個供應商的金鑰(目前涵蓋 OpenAI、Anthropic、AWS、Stripe、Groq、Replicate、OpenRouter、xAI、Fireworks、DeepSeek、Supabase、Clerk),印出撤銷頁面與支出上限設定的連結;你確認後才會開瀏覽器,按 Enter 後才會複掃驗證。引導式,不會自動撤銷金鑰——LeakBolt 沒有你的供應商帳號權限,也做不到。複掃只能看出「這個字串還在不在暫存區」,看不出金鑰本身是否真的已被撤銷,那一步永遠要你自己去供應商網站確認。目前只認得scan --staged留下的指紋,scan --history的命中還沒接上這個指令。untrack <檔案路徑>:把誤被 git 追蹤的憑證檔移出版控。doctor:健康檢查,看 hook 是不是還有效,並回報目前是全域模式或單一 repo 模式。purge-backups:清掉明文備份。
macOS 上 commit 被擋時,除了既有的終端機輸出,會額外跳出原生對話框,顯示檔案、規則與指紋(不顯示命中的原始內容)。單筆命中時提供「標為誤報並放行」按鈕,預設按鈕是「知道了」;兩筆以上只提供「知道了」。對話框 120 秒無回應自動關閉,視同「知道了」。
視窗只是附加提示:非 macOS、CI 環境變數非空、無圖形介面的環境,或 osascript 失敗時都不會顯示,且不影響掃描結果與 exit code——擋下的仍然照擋。
關閉方式:設定環境變數 LEAKBOLT_NO_GUI,或執行 git config leakbolt.gui false。
- 單一 repo 停用:執行
git config hooks.leakbolt false。停用期間每次 commit 會印出一行提醒,leakbolt doctor會回報異常並提供恢復指令。恢復:git config --unset hooks.leakbolt。 - 解除全機保護:執行
leakbolt uninstall --global。 - 只關視窗提示:設定
LEAKBOLT_NO_GUI環境變數,或執行git config leakbolt.gui false。掃描與攔截不受影響。 - 單次跳過:使用
git commit --no-verify,但會同時跳過該 repo 的所有其他 hook。
除了 gitleaks 內建規則,LeakBolt 自帶補充規則,涵蓋 gitleaks 沒收但官方有公開格式的供應商:Groq、Replicate、OpenRouter、xAI、Fireworks、DeepSeek、Supabase secret key 與 PAT、Clerk secret key。規則內嵌在執行檔裡,不依賴外部檔案。
同時刻意排除設計上就該公開的金鑰以避免誤報:Clerk publishable、Stripe publishable、Supabase publishable 與 anon key。但排除規則不涵蓋「只寫 NEXT_PUBLIC_」的情況——把 service_role key 放進 NEXT_PUBLIC_ 變數本身就是嚴重洩漏,照常抓取。
偵測品質基準語料庫共 40 個樣本(19 個真陽性、21 個假陽性),在這組基準上漏報率 0%、誤報率 0%,可用 sh scripts/quality_gate.sh 重跑。這是基準測試集的數字,不是真實世界的保證——實際 repo 的誤報情形見下面「已知限制」第 6 條。
測試資產路徑濾除:gitleaks 預設的 generic-api-key、square-access-token、private-key 這三條屬於高熵猜測型規則,在測試檔與測試資料夾裡命中率極高但幾乎都是雜訊。scan --history 會濾掉這三條規則落在測試路徑(*_test.go、*.test.js、*.spec.ts、test_*、testdata/、fixtures/、__tests__/、tests/、spec/ 等)的命中,並在摘要末尾回報濾掉幾筆;設定 LEAKBOLT_NO_TEST_FILTER=1 可看完整結果。
濾除只套用在歷史掃描,scan --staged(真正擋下 commit 的那條路徑)維持完整靈敏度不濾。LeakBolt 自帶的補充規則也一律不濾——測試檔裡出現真的供應商金鑰仍然是洩漏。
- macOS:相容矩陣 11/11 通過,有預編譯檔與
.pkg安裝檔(未簽章)。視窗提示僅在 macOS 上運作。 - Linux:相容矩陣 11/11 通過,但沒有預編譯檔,要自己編。無視窗提示。
- Windows:真實 Windows + Git Bash 上
go test ./...全數通過(7 個 POSIX-only 測試依設計 SKIP),並已驗證 install、scan、密鑰攔截基本流程與install --globalhook 串接。完整scripts/windows_matrix.ps1相容矩陣及 husky/lefthook/pre-commit 整合情境尚未測試。
git 的 core.hooksPath 是單一值,設了就完全取代原本的 hook 目錄,不會合併。husky、lefthook、pre-commit 都靠這個設定運作,所以在同一個 repo 裡,後設定的那個會接管全部。
實測(2026-09-02,macOS)三種工具的行為:
| 工具 | 在全機保護已開啟時執行它的 install | 後果 |
|---|---|---|
| husky v9 | 照裝不誤,設 repo 層級 core.hooksPath=.husky/_ |
全機保護被蓋掉,該 repo 的 commit 不再經過 LeakBolt |
| lefthook 2.1.12 | 不拒裝,印警告並提供 lefthook install --reset-hooks-path 選項 |
照那個提示做會刪掉全域設定,全機保護整台機器失效 |
| pre-commit 4.5.1 | 拒裝,回報 [ERROR] Cowardly refusing to install hooks with core.hooksPath set. |
保護仍在,但使用者裝不了 pre-commit |
遇到這些情況怎麼辦:在那個 repo 執行一次 leakbolt install。它會偵測到該工具,把檢查寫進對應的位置(.husky/pre-commit、lefthook.yml、.pre-commit-config.yaml),插在既有指令前面,兩者共存。之後 leakbolt doctor 會回報正常。
怎麼知道自己中了:執行 leakbolt doctor。它會指出是哪一層的設定蓋掉全機保護、該跑什麼指令。但它不會自動執行——裝完 husky/lefthook 之後請主動跑一次。
已知無解:lefthook install --reset-hooks-path 會直接移除全域 core.hooksPath,靜默解除整台機器的保護。git 層沒有辦法攔截,只能事後靠 leakbolt doctor 發現。
掃描過程出錯一律中止 commit(fail-closed),不會因為「掃不動」就放行:
- gitleaks 以非 0、非 1 的狀態離開(設定損毀、repo 讀不到、內部錯誤)——即使它同時輸出了合法的 JSON 報告,也視為掃描失敗,不當成「找到 0 筆」。
- 補充規則暫存檔寫不出來(例如
TMPDIR不可寫)——中止並提示,不會退回只用 gitleaks 預設規則掃。降級會讓只有補充規則抓得到的金鑰(Groq、Supabase secret、Clerk secret 等)整批通過,而畫面上仍寫著「找到 0 筆」。 - 找不到 gitleaks、JSON 解析失敗、
state.json讀寫失敗——同樣中止。
唯一會放行的例外是使用者明確要求的:git config hooks.leakbolt false 與 git commit --no-verify,兩者都會留下訊息。
-
hook 擋不住所有路徑。
git commit --no-verify、不經 git 的部署、部分 GUI git 客戶端、hook 被其他工具改寫,都能繞過。請把它當第一層防護,不是保證。特別注意 repo 層級或 worktree 層級的
core.hooksPath會蓋過全機保護,而且是靜默的——除非你主動跑leakbolt doctor,不會有任何提示。詳見上面的與其他 hook 工具共存。 -
把金鑰搬進
.env不等於修好。 如果那個金鑰曾經進過 git 歷史,就算搬走也必須去供應商那邊作廢重發。另外某些前端框架會把特定前綴的環境變數編進瀏覽器 bundle。 -
規則會過期。 鎖定 gitleaks 版本能給穩定基線,但新的供應商與新的 key 格式會繼續出現,不更新就會漏報。
-
scan --history在大型 repo 上很慢。 在golang/go的 4215 個 commit 上實測 53~56 秒(Apple Silicon)。install會跑一次這個掃描,所以大型 repo 的安裝會等上將近一分鐘。相對地scan --staged(每次 commit 實際跑的那個)實測 0.2~0.3 秒,日常 commit 感覺不到延遲。 -
誤報記錄只存規則 ID 與不可逆指紋,不存原始命中內容。
-
真實 repo 仍會有誤報。 實測 5 個公開專案的完整歷史:
gin-gonic/gin4 筆、caddyserver/caddy5 筆、golang/go257 筆,expressjs/express、sharkdp/bat、junegunn/fzf各 0 筆——命中的全部是測試資產,真洩漏 0 筆。加入測試路徑濾除後,gin 降到 0 筆、golang/go 降到 23 筆(剩下的是密碼學實作檔裡的高熵常數,不在測試路徑上)。也就是說:誤報變少了,但沒有歸零,這類專案仍需搭配leakbolt allow使用。
發現漏洞請走 私密回報,不要開公開 issue。哪些算漏洞、哪些是已知的設計限制,見 SECURITY.md。
見 CHANGELOG.md。
MIT。詳見 repo 根目錄的 LICENSE。
gitleaks 本身也是 MIT,LeakBolt 是以子程序方式呼叫它的執行檔,不是鏈結函式庫。
