12 次提交、0 次合併:我在開源 AI 安全社群學到的事
12 次提交、0 次合併:我在開源 AI 安全社群學到的事
我們做了一個 LLM prompt 防禦掃描器 — prompt-defense-audit。掃描系統提示詞,用純 regex 偵測 12 種攻擊向量是否有防禦。不用 LLM、不用 API、5 毫秒跑完。
背後有實際資料:掃了 1,646 個正式環境系統提示,發現 97.8% 沒有間接注入防禦,平均分數 36/100。
我們覺得這個研究有價值,決定貢獻回開源社群。
然後花了兩週學到一個痛苦的教訓。
大撒網
我們向 12 個開源專案提交了 PR 或 Issue:
| 專案 | 類型 | 結果 |
|---|---|---|
| NVIDIA garak(7,500⭐) | PR #1669 | 被關閉 |
| Cisco AI Defense skill-scanner | Issue #81 | 被關閉 |
| OWASP LLM Top 10 | PR #816 | 無回應 |
| Anthropic cookbook | PR #502 | 無回應 |
| Microsoft agent-governance-toolkit | Issue #821 | 後來有回應 |
| Microsoft presidio | Issue #1933 | 無回應 |
| awesome-llm-security | PR #134 | 無回應 |
| awesome-ai-tools | PR #1031 | 無回應 |
| Awesome-Prompt-Engineering | PR #91 | 無回應 |
| agent-audit | Issue #5 | 無回應 |
| NVIDIA NeMo-Guardrails | Issue #1764 | 無回應 |
12 個提交。0 個合併。2 個直接被關。9 個沒人理。
為什麼全部失敗
回頭看,原因很明確。
錯誤一:用同一把鑰匙開所有的門
我們把同一套 YAML 格式的「防禦姿態 pattern」提交給不同的專案。每個專案都有自己的架構、自己的程式語言、自己的 plugin 格式。我們完全沒有去理解。
NVIDIA garak 是 Python 框架,核心概念是 Probe(產生攻擊)和 Detector(評估回應),用 class 繼承、有 detect() method、要跑 pytest。
我們提交了 6 個 YAML 檔案。
維護者 Jeffrey Martin 的回覆:
"Declining as this PR does not even attempt to integrate with garak usage and code standards."
他說得對。我們提交了一份規格書,但他們要的是可以跑的 Python 模組。
錯誤二:做好了再問
garak 的創建者 Leon Derczynski(ITU Copenhagen 教授)其實有在 issue 裡問我們一個問題:
"Can you give references to the principles behind the defense assessment approach & quantification method?"
我們沒有回答這個問題,就直接開了 PR。
這等於跳過了「取得共識」的步驟。在開源社群,這是大忌。你應該先在 issue 裡討論方向、確認架構適配,拿到某種程度的認可,然後再寫 code。
「做好了再問」在開源社群不是效率,是傲慢。
錯誤三:跟錯人
在 garak 的 issue 討論中,一位獨立研究者(不是 garak 維護者)很熱情地回應,說「go ahead and open that PR against community_modules/contrib/」。
我們照做了。但那個目錄結構是他自己 repo 的,不是 garak 的。他沒有 merge 權限。
教訓:確認你在跟誰對話。熱情 ≠ 權限。
錯誤四:工具本身不夠格
當維護者點進我們的 prompt-defense-audit repo,他們看到:
- 3 顆星
- 3 個 commits
- 0 個 CI/CD
- 0 個 test framework(只有一個手寫 assert 的檔案)
- 沒有 CONTRIBUTING.md
- 沒有 SECURITY.md — 一個安全工具,沒有安全政策
這看起來像是一個週末的 side project,不像是一個值得整合進企業級工具的函式庫。
轉折
Cisco AI Defense 的 skill-scanner 拒絕了我們的 issue,但維護者 vineethsai7 說了一句關鍵的話:
"I don't think this is part of the scope of skill-scanner. If you think the MCP specific ones can fit in the MCP scanner, please open a PR there!"
他把我們導向了 mcp-scanner。
這次我們換了方式。
先讀 code,再寫 code
我們花時間讀透了 mcp-scanner 的架構 — 它的 threat detection 模組怎麼寫、test 怎麼跑、Python code style 是什麼。然後用他們的語言寫了一個 Prompt Defense Analyzer,不是用我們自己的 YAML 格式。
同時打磨工具
我們把 prompt-defense-audit 從玩具升級到專業:
- 手寫 assert → Vitest,84 個測試,100% coverage
- 沒有 CI → GitHub Actions,Node 20/22 matrix,badge 亮綠燈
- 沒有文件 → CONTRIBUTING.md、SECURITY.md、CHANGELOG.md、issue templates
- 3 個 commits → 有 release notes 的 v1.3.0
正確回覆 garak
回到 garak 的 issue,我們回答了 Leon 的方法論問題:
- 附上學術引用(Greshake et al. 2023 間接注入、Schulhoff et al. 2023 注入分類學、OWASP LLM Top 10)
- 承認 PR 架構錯誤
- 提出兩個用 Python probe/detector 重做的方向
- 明確說「我想先取得共識再寫 code」
然後等。
第一個 Merge
Cisco mcp-scanner PR #146 — 從開 PR 到合併:51 分鐘。
說實話,這不是一個高難度的技術成就。mcp-scanner 是新專案,積極吸收貢獻,門檻相對低。我們的 PR 是純新增(955 行新增、0 行刪除),不碰現有 code,reviewer 沒什麼要擔心的。
但它代表一件事:我們學會了用對方的語言說話。
目前的狀態
| 專案 | 狀態 |
|---|---|
| Cisco mcp-scanner | 已合併 ✅ |
| NVIDIA garak | 等待維護者回覆 — 方向對了,結果未知 |
| Microsoft agent-governance-toolkit | 有正面互動 — 維護者提出合作方向 |
| 其餘 9 個 | 靜置 |
一個 merge 不算成功。但零個 merge 到一個 merge 之間的距離,比一個到十個還遠。
給正在被拒的人
如果你也在嘗試貢獻開源 AI 安全專案,這是我們付了學費換來的經驗:
1. 先在 issue 討論,等有共識再寫 code。
大多數被拒的 PR 不是因為 code 不好,是因為方向沒對齊。一個 issue 裡的三句話討論,可以省你一週的工作。
2. 用對方的語言寫。
如果專案用 Python,你就用 Python。如果他們有自己的 base class,你就繼承那個 base class。不要發明自己的格式然後期望別人來適應你。
3. 你的工具要配得上你的野心。
如果你要向 NVIDIA 和 Cisco 提交貢獻,你的 repo 不能長得像一個週末專案。CI、測試、文件、安全政策 — 這些不是裝飾,是維護者判斷你是否可靠的信號。
4. 被拒不是終點,是資訊。
「不在我們的 scope」→ 表示你要找對的 repo。 「沒有整合我們的架構」→ 表示你要讀他們的 code。 「可以提供方法論引用嗎?」→ 表示他們有興趣,但需要你證明嚴謹度。
每一次拒絕都在告訴你下一步該往哪走。
5. 確認你在跟誰說話。
熱情的回覆 ≠ merge 權限。看清楚對方是 maintainer、contributor、還是路人。
這篇文章會更新
garak 的故事還沒結束。如果 Leon Derczynski 接受我們的方向,我們會用 Python 寫一個正式的 probe/detector 模組,那會是一個真正的技術挑戰。如果被拒,我們也會寫出來。
開源貢獻不是英雄故事,是反覆碰壁然後學會轉彎的過程。
本文作者是 Ultra Lab 團隊,我們做 AI 安全工具。prompt-defense-audit 是 MIT 開源,歡迎貢獻。