每個 GitHub Actions 作業都會取得一個權杖。GitHub 會在每個作業開始時建立一個全新的 GITHUB_TOKEN,其範圍限定於工作流程所在的儲存庫,作業中的任何步驟都能使用它。它能做什麼,取決於許多團隊從未檢查過的設定,而在較舊的儲存庫中,答案仍然是「幾乎所有內容都能寫入」。
當作業中的某個環節變成惡意時,這點就很重要。在 2025 年 8 月的 Nx「s1ngularity」入侵事件中,該儲存庫的權杖仍具有讀取與寫入權限。pull_request_target 工作流程中的注入攻擊利用它觸發發布工作流程,進而外洩了被用來發布 Nx 惡意版本的 npm 權杖。若權杖是唯讀的,這一步就會被擋下。
本文說明權杖的權限如何設定、各項常見任務需要哪些權限,以及如何為您的工作流程找出最小權限。
GITHUB_TOKEN 是什麼
GITHUB_TOKEN 是 GitHub Actions 應用程式的安裝存取權杖。它有幾個容易被忽略的特性:
- 無論您是否使用,它都存在。 工作流程以
secrets.GITHUB_TOKEN參照它,但任何 action 即使沒有被傳入權杖,也能透過github.tokencontext 讀取它。 - 預設會寫入磁碟。
actions/checkout會為後續的 git 指令保存權杖,除非您設定persist-credentials: false。v6 之前它會寫入.git/config;v6 將它移到$RUNNER_TEMP下的另一個檔案。2024 年,Unit 42 的 ArtiPACKED 研究發現,權杖會透過包含.git/config的建置產物外洩。 - 它隨作業一起失效。 在 GitHub 託管執行器上,這代表最長 6 小時,也就是作業的時間上限。在自架執行器上,它最長可更新至 24 小時。
由於權杖始終存在,您唯一能控制的就是它能做多少事。
預設值:permissive 或 restricted
每個企業、組織與儲存庫都有權杖的預設值:
- Permissive: 所有權限皆可讀取與寫入。
- Restricted:
contents與packages唯讀,其他皆無。
自 2023 年 2 月 2 日起,新的企業、組織與儲存庫預設為 restricted。這項變更並未影響既有的設定,因此在此之前建立的任何儲存庫或組織,除非有人更改過,否則仍保留 permissive 預設值。若較上層選擇了 restricted,其下的層級就無法選擇 permissive。
請在 Settings → Actions → General → Workflow permissions 中檢查,先從組織層級開始。同一區塊還有 Allow GitHub Actions to create and approve pull requests,除非有工作流程需要,否則應保持關閉。
permissions 鍵
工作流程中的 permissions 鍵會從預設值調整權杖的權限。它在兩個層級運作:
permissions:
contents: read
jobs:
release:
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<full-commit-sha>
規則如下:
- 作業層級會覆寫工作流程層級。 將工作流程預設設為唯讀,只在需要的作業中提高權限。
- 任何未列出的權限都會變成
none。 只要設定了一項權限,其他所有權限都會被移除。permissions: {}會移除全部權限。 - 值可以是
read、write或none。write包含read。read-all與write-all會一次設定全部權限;請避免使用write-all。
截至 2026 年 9 月可用的權限:
| 權限 | 控制範圍 |
|---|---|
actions | 工作流程執行、建置產物與快取 |
artifact-metadata | 建置產物中繼資料紀錄(2026 年起在這些 API 上取代 contents) |
attestations | 建置產物證明 |
checks | 檢查執行與檢查套組 |
code-quality | 程式碼品質結果,例如覆蓋率報告 |
contents | 儲存庫內容、commit、分支、標籤與版本 |
deployments | 部署 |
discussions | Discussions |
id-token | 請求 OIDC 權杖(僅限 write 或 none) |
issues | Issue 與留言 |
packages | GitHub Packages,包括容器登錄庫 |
pages | GitHub Pages 建置 |
pull-requests | Pull request、標籤與審查 |
security-events | 程式碼掃描警示與 SARIF 上傳 |
statuses | Commit 狀態 |
vulnerability-alerts | Dependabot 警示(僅限 read 或 none) |
當作業缺少所需的權限時,API 呼叫會以 403 Resource not accessible by integration 失敗。這個錯誤是提醒您為該步驟加上它需要的那一項權限,而不是改用 write-all。
常見任務需要哪些權限
| 任務 | 權限 |
|---|---|
| 簽出程式碼 | contents: read |
| 建立版本或推送標籤 | contents: write |
| 在 issue 或 pull request 上留言 | issues: write(pull request 留言透過 issues API 進行) |
| 為 pull request 加上標籤或審查 | pull-requests: write |
| 以 OIDC 向雲端供應商驗證 | id-token: write |
| 建立建置產物證明 | id-token: write、attestations: write、contents: read,容器映像檔另需 packages: write |
| 將映像檔推送到 GitHub Container Registry | packages: write |
| 將 SARIF 上傳到程式碼掃描 | security-events: write |
| 從工作流程部署 GitHub Pages | pages: write、id-token: write |
大多數測試與建置作業除了 contents: read 之外不需要任何權限。
Fork、pull_request_target 與 Dependabot
- 來自 fork 的 pull request 在
pull_request事件中會取得唯讀權杖,無論工作流程要求什麼,除非管理員開啟「Send write tokens to workflows from pull requests」。請保持關閉。 pull_request_target即使是來自公開 fork 的 pull request,也會取得可讀寫的權杖。這就是許多知名權杖竊取事件的根源:Nx 入侵事件、2024 年 12 月的 Ultralytics 入侵事件,以及 2026 年 3 月的 Trivy action 入侵事件,都始於一個pull_request_target工作流程。GitHub 正在收緊它:自 2026 年 7 月起,actions/checkout預設拒絕在這類工作流程中簽出 fork 的程式碼,而自 2026 年 11 月 2 日起,沒有自訂政策的公開儲存庫將預設停用pull_request_target。- Dependabot 的 pull request 會被視同 fork:取得唯讀權杖,且沒有 Actions 機密。如果您正在評估其他更新工具,請參閱 Dependabot 替代方案。
如何找出最小權限
您不必閱讀每個 action 的原始碼來推敲:
- GitHub Security Lab 的 actions-permissions 會監控工作流程如何使用其權杖,並建議最小權限。目前為公開 Beta。
- OpenSSF Scorecard 的 Token-Permissions 檢查 會標記未在最上層設定唯讀權限的工作流程,並將此檢查評為高風險。
- zizmor 是工作流程的靜態分析工具,會標記過多或預設的權限,以及會保存憑證的簽出。
- StepSecurity 的 Secure-Repo 與 Harden-Runner 會依據 action 知識庫以及作業發出的 API 呼叫,建議作業層級的權限。
實際的導入方式:將組織預設設為 restricted,在每個工作流程最上方加上 permissions: contents: read,然後執行工作流程。以 Resource not accessible by integration 失敗的工作流程,會明確告訴您哪個作業需要哪項額外權限。
CRACI 的定位
最小權限限制了遭竊權杖能做的事,但無法阻止權杖被竊,而作業中的其他機密(例如 npm 權杖與雲端憑證)同樣暴露在風險中。
CRACI 在自己的執行器上執行您的 GitHub Actions 作業。您只要將 runs-on 改為 craci;GITHUB_TOKEN、permissions 鍵與儲存庫設定都照常運作,因為權杖仍由 GitHub 核發。CRACI 增加的是執行器上的能力:決定作業可連線到哪些主機、在作業開始前完成驗證並採失效即封鎖的對外連線政策,以及作業擷取的每個套件的紀錄與其網路連線的追蹤紀錄。即使作業中的惡意程式碼真的取得了權杖,政策也會限制它能傳送到哪裡,而紀錄會顯示發生了什麼事。
關於作業中的其他機密,請參閱 GitHub Actions 機密:如何外洩以及如何鎖定。預約示範,看看您自己的一次建置所留下的紀錄。
