AI-LECTURER 速報課|2026-08-18|約 28 分鐘

Copilot 說『沒問題』,5 天後另一支 AI 就駭進了 Snowflake 的 Jira

📍 真實場景
陳工程師,某新創公司的資深後端工程師,平常負責維護公司在 GitHub 上的自動化流程

他剛用 GitHub Copilot 幫忙審查一個修改自動化腳本的 PR(程式碼修改提案),Copilot 顯示已通過、沒有發現問題,他就放心地按下合併鍵

😖 卡住的地方:他一直以為『AI 審查通過』就等於『安全過關』,卻完全不知道還有另一種 AI——專門找漏洞的紅隊工具——正在世界的另一端不間斷掃描這類被 AI 放行的漏洞,而且平均只要幾天就能找到並攻進系統
💡 這堂課會用 Snowflake 真實發生的案例,帶你看懂那個被 Copilot 放行的漏洞到底長什麼樣子、為什麼 AI 審查會漏掉它,以及『AI 對 AI』的資安新時代,對他這種工程師代表什麼

🧭 這到底是什麼(白話版)

這是一場真實發生的『AI 抓漏洞、AI 也放過漏洞』的對決。資安公司 Wiz 有一套叫做 Red Agent 的工具,角色是紅隊(Red Team)資安圈的角色扮演:找一群人,或這次事件裡的 AI,站在「攻擊者」的立場,主動嘗試入侵自己(或客戶)的系統,藉此提早找出真正的漏洞,專門負責「主動攻進系統,看看到底能闖多遠」。這次它的目標,是雲端資料公司 Snowflake 對外公開讓資安研究員測試的一個 GitHub 專案,而它闖進去之後,一路摸到了 Snowflake 內部拿來追蹤工作進度的 Jira 系統。

問題出在一段負責「自動回覆 GitHub issue(問題回報)」的自動化流程上。這段流程用的是 GitHub ActionsGitHub 內建的自動化工具,能在程式碼有變動、或有人開新問題(issue)時,自動幫你跑一連串預先寫好的動作,它有個壞習慣:直接把「issue 標題」這種任何路人都能填寫的文字,整段貼進要交給電腦殼層執行的指令字串裡。這正是經典的 腳本注入(script injection)駭客把原本應該只是「一段文字」的內容,塞進系統會拿去執行的指令裡,讓系統誤把這段文字當成「指令」來執行 手法——攻擊者只要在標題裡藏一個單引號,就能讓那段文字提前「變身」成真正會被執行的指令。

更值得玩味的是,這個漏洞不是憑空冒出來的,而是五天前一份 Pull Request(PR)工程師想把自己修改的程式碼併入正式版本前,先提出來讓別人(或這次事件裡的 AI)審查的一份「修改提案」 親手「升級」進去的——原本比較安全的寫法被換成了這種直接貼字串的危險寫法,而且合併紀錄上還掛著 GitHub Copilot AutofixGitHub 出的 AI 工具,會自動幫忙檢查程式碼有沒有資安問題,並在 PR 上留言說「這樣改可以」或「這裡有風險」 這個共同作者的名字——它掃過這次合併後的程式碼變更,判定「沒問題」,卻沒看出這個嚴重漏洞。

🎯 為什麼值得你花時間

AI 審查抓不到系統怎麼被組出來的問題Copilot Autofix 很擅長挑程式碼裡的錯字、明顯的邏輯錯誤,但這次的漏洞藏在「GitHub 什麼時候把使用者輸入貼進指令字串」這種基礎設施層級的執行順序裡。這提醒所有依賴 AI 協助審查的團隊:AI 審查是多一層防護,不是唯一的防護,尤其是自動化流程的設定檔,更需要專門的資安掃描工具。
防守和攻擊,比的是誰的 AI 動作更快從漏洞上線到被 Wiz Red Agent 自主找到、利用、驗證影響範圍,只花了 5 天,而且全程沒有人類介入。這代表攻防雙方的反應速度已經被 AI 大幅壓縮——過去可能要排隊數個月的滲透測試,現在幾天內就能跑完一輪,公司不能再用「漏洞要很久才會被發現」的舊假設來評估風險。
任何人都能填的欄位,都可能是攻擊入口這次的破口只是一個誰都能填的 GitHub issue 標題,不是什麼需要權限才能碰到的後台。只要某個欄位的內容最終會被自動化流程拿去組指令、或換取有權限的資源,它就該被當成跟網頁輸入框一樣的不受信任輸入來處理。

⚙️ 它是怎麼運作的

1
安全寫法被換成危險寫法6 月 18 日,一份 PR 把 snowflake-connector-net 這個專案裡原本用來清理使用者輸入的寫法,換成了直接把文字貼進殼層指令字串的寫法,而且順利合併上線。
2
AI 審查掃過,判定沒問題GitHub Copilot Autofix 是這次合併紀錄上的共同作者之一,它掃過合併後的程式碼變更,回報「沒有發現問題」——但沒有看出這裡藏著一個嚴重的腳本注入漏洞。
3
漏洞正式上線,任何人都能觸發這段工作流程設定成「只要有人開一個新 issue 就自動執行」,而開 issue 這件事完全不需要任何內部權限——任何一個有 GitHub 帳號的陌生人都做得到。
4
Wiz Red Agent 自動掃到並嘗試攻擊五天後,Wiz 的自主資安工具 Red Agent 在例行掃描 Snowflake 公開的 GitHub 專案時,標記出這條工作流程有腳本注入風險,並自主嘗試利用它——這整段研究是在 Snowflake 透過 漏洞懸賞計畫(Bug Bounty,這裡指 HackerOne)公司公開邀請外部資安研究員來找自己系統的漏洞,找到就給獎金,讓研究行為在授權範圍內合法進行 授權的範圍內進行的。
5
AI 自己驗證能碰到多少東西確認漏洞真的能被利用之後,Red Agent 接著自主驗證了能不能碰到 Snowflake 內部 Jira 系統裡的敏感資料,並評估這個漏洞的 爆炸半徑(Blast Radius)一旦漏洞被打穿,攻擊者最多能碰到多大範圍的系統或資料,範圍愈大代表這個漏洞愈嚴重——這一整段「發現、利用、評估影響」的過程,全程沒有人類介入。
6
通報、修補、稽核三連發6 月 23 日 Wiz 依規定負責任地通報給 Snowflake,Snowflake 當天就修補了漏洞、完成 憑證輪替(Credential Rotation)把可能已經外洩的密碼、金鑰整組換掉,讓舊的那組就算被偷走了也不能再拿來用,並透過 稽核紀錄(Audit Log)系統背後默默記下「誰、在什麼時候、做了什麼操作」的紀錄檔,事後可以用來確認到底是誰動過某個系統 確認整段過程中只有 Wiz 一方碰過這個漏洞,測試用的資料也已經安全刪除。
同一個弱點,兩種寫法的資安差距
寫法程式邏輯(示意)為什麼安全或危險
❌ 直接把使用者輸入貼進殼層指令字串TITLE=$(echo '${{ github.event.issue.title }}')GitHub 會先把 issue 標題整段文字貼進這行指令,貼完才交給殼層解析——攻擊者只要在標題裡放一個單引號,就能讓字串提前結束,後面的文字變成真正會被執行的指令
✅ 先轉成環境變數,讓殼層讀變數而不是讀字串env: TITLE: ${{ github.event.issue.title }},然後在 run 裡改用 $TITLE使用者輸入的文字被放進獨立的環境變數,不會被直接拼進指令字串本身,殼層只會把它當成一個變數的值來讀,不會被解讀成指令的一部分

🔍 程式碼漫遊(點有 ● 的行看白話講解)

這段是還原自 Snowflake 這次事件核心邏輯的 GitHub Actions 設定檔(簡化版),負責「有人開新 issue 時自動處理」,但裡面藏著這次真正出事的那一行。

on:
💬 這裡開始定義:什麼情況會自動觸發這段流程
issues:
types: [opened]
💬 觸發條件是「有人開一個新的 issue(問題回報)」——任何有 GitHub 帳號的陌生人都做得到,不需要是公司內部的人
jobs:
handle-issue:
💬 這個工作的名字,負責處理剛剛被開出來的 issue
runs-on: ubuntu-latest
💬 指定用哪一種電腦環境來跑這段流程
steps:
- run: |
💬 接下來這一段文字,會先被 GitHub 動手腳,才交給殼層執行
TITLE=$(echo '${{ github.event.issue.title }}' | sed ...)
💬 重點在這裡:GitHub 會先把 ${{ github.event.issue.title }} 換成使用者填的 issue 標題文字,換完之後才把整行交給殼層解讀。如果標題裡藏了一個單引號,字串會在這裡提前『結束』,後面的文字就不再是純文字,而是變成真正會被執行的殼層指令——sed 是在這一步之後才跑,等它想幫忙過濾時,傷害已經造成了

🛠️ 動手做:動手拆解:一個單引號怎麼騙過整條自動化流程

  1. 先按一次「模擬觸發自動化流程」,看看標題是預設的正常文字時,殼層會怎麼處理。
  2. 按下「套用惡意標題」,把輸入框換成一個藏有單引號的 issue 標題。
  3. 再按一次「模擬觸發自動化流程」,觀察下方「殼層實際會執行的內容」有什麼變化。
  4. 留意紅色警示文字:那段被單引號放出來的文字,就是攻擊者真正能塞進去執行的殼層指令。
  5. 自己動手把輸入框改成別的句子,中間加一個單引號,看看能不能重現同樣的提前結束效果。
👇 下面是活的,直接操作

🧠 工程思維透鏡(資深工程師看到的是什麼)

🔭 為什麼「AI 審查通過」不能當成資安的最後一道防線?
Copilot Autofix 擅長抓的是這段程式碼語法有沒有問題、邏輯有沒有明顯 bug,但這次的漏洞藏在 GitHub 模板展開的執行順序這種基礎設施層級的細節裡——不是程式碼寫錯,而是整個系統「先貼字串、後解析」的設計本身就有陷阱。資深工程師看到的是:AI 程式審查的能力邊界,跟這段 YAML 到底安不安全,是兩件不完全重疊的事,所以資安團隊仍然需要專門掃描 CI/CD 設定檔的工具,而不是只靠通用型的 AI 程式碼審查。
🔭 為什麼「5 天就被攻破」同時是好消息也是壞消息?
好消息是:Wiz Red Agent 這種自動化紅隊工具,能把過去可能要排隊數個月才輪到的滲透測試,壓縮到幾天內完成,等於幫防守方把暴露窗口大幅縮短。壞消息是:這也證明攻擊方如果用同等級的自動化工具,同樣能在幾天內找到並利用漏洞——防守速度和攻擊速度現在是同一個量級的軍備競賽,公司不能再假設漏洞要很久才會被找到。
🔭 為什麼這次事件把「不受信任輸入」的範圍重新定義了?
過去工程師直覺會去檢查的使用者輸入,通常是網頁表單、API 參數這種明顯的地方,但這次的攻擊入口只是一個 GitHub issue 標題——一個任何路人都能免費、免審核填寫的欄位。資深工程師看到的設計教訓是:只要某個欄位是網路上任何人都能控制,而且這個欄位的值最終會被自動化流程拿去組指令或存取有權限的資源,它就該被當成跟網頁輸入框一樣不受信任,需要一樣等級的處理。
🔭 這個工作流程一開始為什麼會有能力碰到敏感憑證?
問題的根源不只在沒有過濾輸入,還在於這個處理 issue 的自動化流程,權限範圍設得比它實際需要的還大,才會在被打穿之後直接牽連到 Snowflake 內部的 Jira。資深工程師會接著問的是最小權限原則:一個只是要回覆 issue 留言的工作流程,到底有沒有必要拿到能碰觸內部系統的憑證?把權限收得更小,就算指令注入還是發生了,攻擊者能碰到的爆炸半徑也會小很多。

📝 隨堂考(點選答案,立即回饋)

Q1. 這次 Snowflake 事件裡,漏洞真正發生的位置是?
✅ 問題出在 jira_issue.yml 這個 GitHub Actions 工作流程,把使用者可控的 issue 標題直接嵌進殼層指令字串裡,而不是密碼強度或 Jira 本身的漏洞。
Q2. 為什麼「先用 sed 做轉義」沒能擋下這次攻擊?
✅ 問題不是 sed 語法錯誤,而是執行順序:GitHub 的模板展開發生在殼層真正解析指令之前,攻擊者的單引號在那個當下就已經讓字串提前結束,sed 想過濾時為時已晚。
Q3. 誰有辦法觸發這個有漏洞的工作流程?
✅ 這個工作流程的觸發條件是 issues: opened,代表任何能在這個公開 repo 開 issue 的 GitHub 使用者,都能觸發它——完全不需要任何內部權限。
Q4. Wiz Red Agent 完成「發現漏洞→利用漏洞→驗證能碰到多少資料」的整個過程,有沒有人類介入?
✅ 文章明確指出,從掃描發現、利用漏洞、到驗證能碰觸的資料範圍(blast radius),全程都是 Wiz Red Agent 自主完成,沒有人類介入。
Q5. GitHub Copilot Autofix 在這次事件裡實際做了什麼?
✅ 文章提到 squash commit 把「Copilot Autofix powered by AI」列為共同作者,且更新說明指出 Copilot 有審查過合併後的程式碼變更,判定沒問題,但沒注意到這個嚴重漏洞;至於原始程式碼是否為 AI 協助撰寫則不確定。

🃏 翻牌記憶卡(先想答案,再點開對答)

腳本注入(Script Injection)點我翻面
把原本只該當文字處理的輸入,塞進系統會拿去執行的指令裡,讓文字變成真正被執行的指令
為什麼 sed 的過濾沒擋下這次攻擊?點我翻面
因為 GitHub 會先把使用者輸入的文字整段貼進指令字串(模板展開),貼完才輪到 sed 開始過濾——這時攻擊者的單引號早就已經讓字串提前結束,傷害已經造成
Wiz Red Agent 花了多久找到並攻進這個漏洞?點我翻面
5 天。PR 在 6 月 18 日合併讓漏洞上線,Wiz Red Agent 在 6 月 23 日就自主完成發現、利用、驗證影響範圍,全程沒有人類介入
GitHub Copilot Autofix 在這次事件扮演什麼角色?點我翻面
它是這個 PR 合併後程式碼變更的共同審查者之一,掃過之後判定沒問題,卻沒發現這個嚴重漏洞
誰能觸發這個有漏洞的自動化流程?點我翻面
任何有 GitHub 帳號的人都可以,因為觸發條件是有人開一個新 issue,完全不需要是 Snowflake 內部的人或這個 repo 的協作者
爆炸半徑(Blast Radius)點我翻面
一旦漏洞被打穿,攻擊者最多能碰到多大範圍的系統或資料——這次是 Snowflake 內部的 Jira 系統

✅ 離開前自測(全勾=這課真的學會了)

0%