The Guardrail Company Got Owned. Skill Provenance Is the Layer Below.
On 2026-05-11 the Mini Shai-Hulud npm/PyPI worm trojanized 404 package versions, including @mistralai/mistralai and guardrails-ai. A runtime LLM-output guardrail cannot catch an install-time daemon. ATR v3.1.0 ships ATR-2026-00525 covering the gh-token-monitor signature.
_2026-05-11 那波 Mini Shai-Hulud npm/PyPI 蠕蟲污染了 404 個套件版本,跨 JavaScript 和 Python 生態。其中兩個受害者是大部分團隊預設信任的廠商:Mistral AI(前沿模型 lab)和 Guardrails AI(runtime LLM-output guardrail 提供商)。Runtime 層的 guardrail 攔不住 install time 投放的攻擊。Detection layer 必須在 guardrail 之下。_
中標的東西
Akamai、Wiz、CSA 的研究員追蹤這波到 2026-05-17。Help Net Security 和 The Hacker News 報導了時序。中標清單至少包括:
- ●
@mistralai/mistralai— Mistral 官方 TypeScript SDK on npm。Payload 透過 npmpreparelifecycle hook 投放(和 TanStack 同一個 install vector)。 - ●
mistralai和guardrails-ai— Mistral 和 Guardrails AI 官方 Python SDK on PyPI,payload 由__init__.py的on importside effect 觸發,下載/tmp/transformers.pyz從git-tanstack[.]com。 - ●TanStack packages(
@tanstack/router、@tanstack/query等)— 同一家族,npmpreparelifecycle hook 透過 Bun runtime 投放。 - ●UiPath packages(這波另一個 sub-cluster)用 npm
preinstallhook 呼叫node setup.mjs當 install vector。
Wiz 和 Aikido 的分析估計總共 403 個 trojanized package versions,分布在約 172 個獨立 package 上,累積過去十二個月 5 億 1,800 萬次下載。
Payload 做什麼
這波攻擊有三個 artifact:
1. `gh-token-monitor` — 持續駐留的 daemon,透過 macOS LaunchAgent(~/Library/LaunchAgents/com.user.gh-token-monitor.plist)或 Linux systemd user service(~/.config/systemd/user/gh-token-monitor.service)安裝。Daemon 用開發者的 GitHub token 每 60 秒 poll 一次 api.github.com/user。
2. Dead-man's switch — 當 polled token 回 HTTP 401(開發者輪換或撤銷 token),daemon 對整個 home directory 跑 rm -rf ~/(依 Wiz 和 JFrog 分析)。毀滅動作是條件觸發的,這就是為什麼純靜態 manifest 掃描抓不到 daemon。
3. Exfiltration 通道 — filev2.getsession[.]org(走 Session Protocol)、api.masscan[.]cloud(GitHub Actions secret serialization)、typosquat git-tanstack[.]com 拿來收 credential。83.142.209[.]194 這台 host 已確認在跑 PyPI credential stealer。
Mistral 在 2026-05-12 開了一個公開 security advisory 頁面 docs.mistral.ai/resources/security-advisories,承認 TypeScript SDK 中標。這是 Mistral 第一次跑公開 security advisory 頁面。也是對的動作。
為什麼 runtime guardrail 攔不到這個
Guardrails AI 的產品就是字面意思 — 一個包在 LLM output 外面的 runtime guardrail。它驗證 model response 符合預先宣告的結構和安全約束,才把 response 放給 user 或下游 tool。Lakera、PromptArmor、Protect AI、Lasso Security 以及閉源同類產品都在做一樣的事,在一樣的 layer。
這些產品在他們自己那層做得很好,但他們全都活在 stack 的同一層。沒有一個會去檢查 pip install guardrails-ai 執行時跑的 __init__.py 內容,因為 runtime guardrail 載入的時候,install-time daemon 已經在磁碟上落地三到五分鐘了。Runtime guardrail 定義上就在 install 之後。
這不是針對特定廠商的攻擊。這是一個 layering 觀察。一個 guardrail 廠商自己在 install time 中標,意味著他們產品處理的 threat model 沒有延伸到送他們產品上門的 supply chain。那個 threat 的 detection layer 在更下面。
ATR 為這件事出的規則
Agent Threat Rules v3.1.0 出 ATR-2026-00525 覆蓋 Mini Shai-Hulud 家族。規則對任何到 agent runtime 或 skill scanner 的文字觸發三條 alt:
1. 字面 daemon 名稱 gh-token-monitor、gh_token_monitor,或 LaunchAgent label com.github.token.monitor。
2. 在 500 字元內配對:對 api.github.com/user 的 polling loop + 毀滅性 shell primitive(rm -rf、shutil.rmtree、os.system rm)— 也就是 dead-man's-switch 形狀。
3. 在 300 字元內配對:interval/timer 結構(setInterval、threading.Timer、asyncio.sleep)+ /user poll + shell execution primitive(child_process、exec、毀滅指令)— 也就是 install-time daemon 形狀。
覆蓋度誠實講:規則抓到的是 Akamai、Wiz、Sysdig 公開 writeup 中出現的 canonical IOC。它抓不到 dead-man's-switch pattern 的每一種 obfuscation。規則的 true_negatives block 文件化了刻意接受的 FP case 和明確拒絕的 case。Source 在 Agent-Threat-Rule/agent-threat-rules main 上的 skill-compromise category。
一層一層的偵測 map
對今天在建構或採購 AI security 的團隊來說,layer 是這樣排的:
| Layer | 它檢查什麼 | 這次攻擊在這層長什麼樣 |
|---|
|---|---|---|
| Runtime LLM output guardrail | 生成後的 model response | 看不到 — payload 在 install 跑,從沒到 model。 |
|---|
| Tool call gate / function-call inspector | Tool invocation 的 argument | 看不到 — daemon 是背景 process,不是 tool call。 |
|---|
| MCP / skill content scanner | SKILL.md 文字或 skill code 在 registration 時 | 抓到 — 透過 ATR-2026-00525 抓 daemon-install 形狀和 dead-man's-switch 形狀。 |
|---|
| Package manifest scanner | package.json、pyproject.toml、setup.py 對應已知 IOC string | IOC 還在的時候抓得到 preinstall: node setup.mjs 形狀。 |
|---|
| Process / runtime EDR | LaunchAgent plist 新增、可疑子 process | IOC 還在的時候抓得到 daemon 在 install 階段。 |
|---|
五層裡有三層看不到這次攻擊。能看到的兩層不是 runtime guardrail 廠商所在的層。PanGuard 從 2026 年 3 月 v0.1 開始的 positioning,就是 skill-content layer 加 manifest layer。這不是一句行銷詞。這是這次攻擊真實浮現的層。
我們不主張的事
幾個誠實揭露,讓這篇文不變成廠商 cosplay:
- ●ATR 是被動的。規則裡的
gh-token-monitor字串是一個 IOC;下一個 worm 會用不同 daemon 名稱,規則第一個條件就需要更新。規則第二、第三條件(dead-man's-switch 形狀和 timer-plus-shell 形狀)是 pattern-based,應該 generalize 比較好,但 pattern-based 規則也會有 false negative。 - ●ATR 是 MIT open source。它不是 PanGuard 獨有的。任何人用 ATR 的 npm package、MISP feed,或 Cisco AI Defense scanner config,拿到的是一樣的覆蓋。差異化不在規則本身,在 disclosure 到 shipped rule 的 loop 時間。這次攻擊 disclosure 是 2026-05-11,對應規則 ship 是 2026-05-23,十二天。太慢了。Microsoft Copilot Semantic Kernel 那個 loop 在 2026-05-11 兩小時十六分鐘收尾,是因為 disclosure 帶了可用的 PoC。Mini Shai-Hulud 的 writeup 沒帶,這就是這個 loop 比較慢的結構原因。
- ●對 runtime guardrail 廠商的誠實 framing 是「不同的 layer,兩個都需要」,不是「我們取代他們」。Runtime LLM-output guardrail 抓的是和 skill-content scanner 不同的攻擊類別。成熟的部署會兩個都跑。這篇的 point 是:只跑 runtime guardrail 留下一層沒蓋到。
這週可以做的事
1. 如果你的依賴樹有 @mistralai/mistralai、mistralai 或 guardrails-ai,audit 你的 install:npm ls @mistralai/mistralai + pip show mistralai guardrails-ai。Mistral 的 advisory 頁面列了具體 bad version。Pin 到 patched release。
2. 檢查 persistence daemon:macOS 上 launchctl list | grep -i token-monitor,Linux 上 systemctl list-units | grep -i token-monitor。Daemon 的 plist label 是 com.github.token.monitor,systemd unit 叫 gh-token-monitor.service。
3. 如果你出 agent platform,把 skill-content scan 加進 registration flow。ATR 規則是一個檔加 YAML;它 load 進任何吃 ATR format 的 rule-runner。Microsoft Agent Governance Toolkit、Cisco AI Defense、MISP 今天都在跑。
4. 如果你做 runtime guardrail 產品而且讀到這邊,誠實的 move 是加一個 skill-content 或 package-manifest 的 companion scanner。Runtime layer 是必要的。但它不夠。
收尾
如果你的 AI security architecture 只檢查 runtime output,supply chain 就是你的盲點。Mini Shai-Hulud 是經驗證據。Guardrail 公司被打穿了。Detection layer 必須在更下面。
_Adam Lin 維護 Agent Threat Rules,一個 MIT 授權的 AI agent 威脅偵測 corpus。ATR 規則在 Microsoft、Cisco、MISP 都在跑。同時是 Panguard AI 的 founder(Delaware C-Corp,做 ATR 標準的商業化產品)。聯絡:[email protected]_