GitHub Actions 的 pull_request_target 為何突然擋住 checkout?先分清楚安全邊界
如果你在 pull_request_target workflow 裡更新了 actions/checkout,然後發現 fork 開來的 PR 突然不能 checkout,先不要急著把保護關掉。GitHub 在 2026 年 7 月的更新,讓 actions/checkout v7 預設拒絕常見的 fork PR checkout 模式;目的是阻止高權限 workflow 取得不可信程式碼後又執行它。
直接答案是:需要執行 fork PR 程式碼時,改用 pull_request;只有非用 pull_request_target 不可,而且程式碼只作資料檢視時,才評估明確放行。
先理解為什麼 pull_request_target 危險
pull_request 會使用 PR 的 merge commit,來自 fork 時預設是唯讀 GITHUB_TOKEN,也不提供 secrets。pull_request_target 則使用目標 repository 預設分支的 workflow;它能取得較高權限與 secrets,因此適合標籤、留言等不必執行 PR 程式碼的操作。
問題出在這個組合:高權限的 pull_request_target,checkout fork 的 head,再跑 npm install、測試或 build。套件 lifecycle script、設定檔和 build 工具都可能執行 PR 作者控制的程式碼。GitHub 把這類風險稱為 pwn request。
先找出會受影響的 workflow
在 repository 根目錄搜尋事件、checkout ref 與可能執行程式碼的步驟:
rg -n 'pull_request_target|actions/checkout|github\.event\.pull_request\.head' .github/workflowsrg -n 'npm (ci|install|run)|pnpm (install|run)|yarn|make|pytest' .github/workflows這不是只找 npm。任何下載 artifact、git fetch、gh pr checkout,再把拿到的內容交給 shell、建置工具或解譯器的流程,都要當成不可信程式碼路徑檢查。
三種情境,選不同修法
| 需求 | 建議事件 | 原因 |
|---|---|---|
| lint、test、build fork PR | pull_request | 讓 GitHub 維持 fork 的唯讀 token 與 secrets 隔離。 |
| 依 PR metadata 加 label 或留言 | pull_request_target,不 checkout PR code | 只取 event payload,不碰不可信工作樹。 |
| 讀取 PR diff 做靜態分析 | 優先 API 讀取;必要時獨立目錄 checkout,且永不執行 | 將「讀取資料」與「執行程式碼」拆開。 |
例如一般 CI 不必使用 pull_request_target:
name: teston: pull_request:
jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v4 - run: npm ci - run: npm test不要把 allow-unsafe-pr-checkout 當成修復
actions/checkout 提供 allow-unsafe-pr-checkout: true,是讓已確認安全的特殊情境明確 opt out。這個名稱刻意很醒目:它不是相容性旗標,而是讓 code review 能看見風險決定。
即使真的必須使用,也先做到:不提供 secrets、最小化 permissions、把 PR checkout 到獨立路徑、後續不執行該路徑內容,並寫下為什麼 API 或 pull_request 不可行。只要會執行 PR 的安裝、測試或 build,這個旗標就不是正確解法。
一次發布前檢查
- fork PR 的 CI 是否一律由
pull_request執行? pull_request_targetworkflow 是否完全不 checkout 或執行 PR code?- 是否還有
git fetch、artifact download 或gh pr checkout繞過 checkout 的保護? - 任何明確放行是否有最小權限、無 secrets 與可供審查的原因?
這次變更不是要讓 workflow 不能碰 PR,而是要求高權限事件不能把不可信程式碼直接送進執行路徑。把事件用途分開,通常比增加例外更容易維護。
常見問題
Q: 同一個 repository 的 PR 也會被擋嗎?
A: GitHub 的這次保護針對 fork pull request 的 head ref;同 repository PR 與一般 pull_request 流程不在這個預設阻擋範圍。不過任何高權限 workflow 執行未審核程式碼,仍應依同一套最小權限原則檢查。
Q: 我只想讀 PR 的 diff,還需要 checkout 嗎?
A: 通常不需要。優先用 GitHub API 或 event payload 取得 metadata 與 diff;這能避免把不可信檔案寫入 workflow 工作目錄。若一定要取得檔案內容,必須確保它只被當資料處理,絕不被 shell、建置或測試步驟執行。
參考資料:
回報錯字、失效連結,或告訴我你想看的延伸主題。