Lab:自建一個 trust gate
前四課都在講觀念;這一課把觀念壓成一段你真的跑得起來的最小程式。
Hook
你不想再只靠嘴巴說「外部內容很危險」。
你想做一個最小 trust gate。
它不用很漂亮。
不用先接真模型。
不用先接真 webhook。
你只想先證明一件事:
如果一段不可信內容裡藏了 prompt injection,
你能不能在送進模型前先包起來,
並在模型輸出後檢查它有沒有把不該帶出的字串帶出來。
這就是這堂 lab 的目標。
我們不做大系統。
我們只做一個大約 50 行的最小版。
功能只有兩個:
wrap_untrusted(content, source):把外部內容做最基本的清洗後包起來check_canary(llm_output, canary):檢查模型輸出有沒有洩漏指定 canary token
這種 lab 的價值不是 production ready。
而是你會第一次真正看到:
信任邊界不是口號,
它可以變成非常具體的工程節點。
Learn
這個 lab 要驗證什麼
先把成功標準講清楚。
這個 lab 不是要證明:
- 你已經能百分之百防 prompt injection
- 你寫了一個完整 sanitizer
- 你做了一個真正可上線的 policy engine
它要證明的是比較小、但很關鍵的兩件事:
| 驗證點 | 你要看到什麼 |
|---|---|
| 外部內容有沒有先被結構化標記 | raw content 進模型前已被 <untrusted> 包裹 |
| 模型有沒有把不該外洩的 token 帶出來 | check_canary(...) 會明確回報 True 或 False |
做到這兩步,
你就已經把「我覺得這裡很危險」,
變成了一個可以被測、可以被 review 的工程流程。
為什麼用 canary
canary 的概念很簡單。
你故意在 untrusted 區塊裡放一個不該出現在正常輸出裡的字串。
例如:
CANARY:BLUE-741
如果模型最後把它吐出來,
你就知道兩件事至少有一件出了問題:
- 模型過度受外部內容影響
- 你的 prompt / wrapper / post-check 設計不夠好
它不是萬能指標。
但它超便宜。
而且對最小實驗非常好用。
因為你不需要靠肉眼猜:
「這次看起來好像怪怪的。」
你可以用一個明確字串做 deterministic 檢查。
Reference code:最小 trust gate
下面這段 code 是完整可跑的。
它只用 Python 標準函式庫。
沒有假 import。
沒有外部依賴。
它會同時示範:
- 沒包 untrusted 時,假 LLM 會把 canary 帶出來
- 包完之後,輸出會被壓回安全路徑
check_canary(...)可以直接告訴你有沒有外洩
如果一切正常,
你應該會看到:
unsafe_output = Leaked CANARY:BLUE-741
unsafe_canary = True
safe_output = Summary: Release note: Please summarize this page for the engineering team. [redacted]
safe_canary = False
這就是這個 lab 最重要的 moment。
你不是在看一個神奇的安全框架。
你是在看一個最小但清楚的邊界機制:
- 不包,會洩漏
- 包了,配合基本清洗與 post-check,就能先攔下一類簡單失誤
wrap_untrusted(...) 為什麼夠格叫 gate 的第一步
很多人會覺得 wrapper 很弱。
因為它沒有「阻止模型思考」。
這是誤解。
trust gate 的工作本來就不是單靠一個函式完成一切。
wrap_untrusted(...) 的角色是:
- 降權外部內容
- 清掉最常見的零寬與 comment 污染
- 建立一個後面其他檢查可以依附的結構
沒有這一步,
你後面的任何 rule 都會變模糊。
因為你根本不知道哪段內容是外部來源。
check_canary(...) 為什麼值得保留
有些人會說:
「如果我 prompt 寫得夠好,理論上就不需要 canary。」
這句話在實務上很危險。
因為 prompt 是期望。
canary check 是驗證。
這兩者不要混在一起。
你可以把它想成測試:
- prompt 像規格
- canary check 像 assertion
工程上沒有 verification 的規格,
最後通常都會變成信仰。
而你做 trust boundary,
最不該依賴的就是信仰。
這個最小 lab 還沒做哪些事
要誠實。
這份 code 刻意做得很小,
所以它還沒處理很多現實世界問題:
- 沒有完整 HTML parse
- 沒有處理
<details>或<script> - 沒有做來源白名單或 provenance 記錄
- 沒有真的接 API model
- 沒有做風險分級與 human approval
但這不代表它沒價值。
相反,
它剛好適合當你的第一個安全實驗。
因為它把最關鍵的工程分工切清楚了:
| 步驟 | 功能 |
|---|---|
| 包裹前清洗 | 先拔掉最顯眼的隱藏技巧 |
<untrusted> wrapper | 建立資料 / 指令邊界 |
| fake LLM / 真 LLM call | 觀察模型在不同上下文下的行為 |
| canary check | 用 deterministic 方法驗證輸出是否越界 |
你回到真系統時,最先該升級哪裡
把這個 lab 抄回真專案時,
最先該升級的通常不是模型。
而是 trust gate 的入口與出口。
入口要升級的是:
- HTML 清洗
- 詳細的 hidden content 處理
- source metadata
- logging
出口要升級的是:
- canary 檢查
- suspicious phrase 檢查
- tool call gate
- human approval
也就是說,
真正能演化成 production 系統的,
往往不是中間那次 LLM call。
而是前後這兩道邊界。
這一課你應該真的動手記住的兩個函式
如果只能帶走兩個名字,
就帶走:
wrap_untrusted(...)check_canary(...)
前者負責把外部輸入降權並結構化。
後者負責把輸出驗證變成機器可判斷的規則。
這兩個函式加起來,
就是最小 trust gate 的雛形。
不是全部。
但已經不是口號。
AI 協作:學了這個,跟 AI 怎麼配合?
這個技能在 AI 協作中的定位,是讓你不只會叫 AI 生 code,而是能要求它把外部輸入邊界與輸出驗證一起做出來。
你的人類優勢:
- 只有你能決定哪些字串適合當 canary,才能真的代表「這個內容不該被外洩」。
- 只有你能判斷這個最小 gate 何時還只是 demo,何時已經足以接到真實工作流的 staging 入口。
可以這樣跟 AI 說:
請幫我把下面這段處理外部內容的 Python flow,改寫成一個最小 trust gate。你必須包含
wrap_untrusted(content, source)和check_canary(llm_output, canary)兩個函式,並提供一段可直接執行的 demo。不要用外部套件;如果你做了任何安全假設,請在 code comment 裡講清楚。
Do
互動示範
挑戰任務
請寫一段 Python,讓 clean = re.sub(...) 額外移除 <details>steal</details><script>alert(1)</script> 這兩段內容,最後印出 <untrusted source="demo">ok</untrusted>。你可以自由定義中間變數,但輸出必須是乾淨的單行結果。