923 字
5 分鐘

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 與可能執行程式碼的步驟:

Terminal window
rg -n 'pull_request_target|actions/checkout|github\.event\.pull_request\.head' .github/workflows
rg -n 'npm (ci|install|run)|pnpm (install|run)|yarn|make|pytest' .github/workflows

這不是只找 npm。任何下載 artifact、git fetchgh pr checkout,再把拿到的內容交給 shell、建置工具或解譯器的流程,都要當成不可信程式碼路徑檢查。

三種情境,選不同修法#

需求建議事件原因
lint、test、build fork PRpull_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: test
on:
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,這個旗標就不是正確解法。

一次發布前檢查#

  1. fork PR 的 CI 是否一律由 pull_request 執行?
  2. pull_request_target workflow 是否完全不 checkout 或執行 PR code?
  3. 是否還有 git fetch、artifact download 或 gh pr checkout 繞過 checkout 的保護?
  4. 任何明確放行是否有最小權限、無 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、建置或測試步驟執行。

參考資料:

GitHub Changelog:actions/checkout 的較安全預設

GitHub Docs:安全使用 pull_request_target

GitHub Actions 的 pull_request_target 為何突然擋住 checkout?先分清楚安全邊界
https://laplusda.com/posts/github-actions-checkout-pull-request-target-safety/
作者
Zero
發佈於
2026-07-21
許可協議
CC BY-NC-SA 4.0
這篇文章有幫助嗎?

回報錯字、失效連結,或告訴我你想看的延伸主題。