What changed, and why it matters
This commit tightens the security settings on the project's GitHub Actions workflows. Previously, these automated scripts likely ran with broad default permissions that could let a compromised action read or modify code, open pull requests, or access secrets. The change sets the default permission to 'none' and then explicitly grants each workflow only the minimum permissions it actually needs (mostly just reading the repository, with write access only where required). This is a defensive hardening measure rather than a fix for an active attack.
Review the job-level permission grants to confirm they are truly minimal; in particular, verify that `manage-pr.yml` still functions correctly with no permissions and consider whether it needs any explicit read-only grants. Continue pinning third-party actions to specific commit hashes and audit them for permission requirements. Apply the same `permissions: {}` default to any new workflows.
Security signals we found
Least-privilege GitHub Actions token hardening
Workflow-level default permissions set to empty (`permissions: {}`)
Job-level explicit permission grants replace broad defaults
Dangerous `pull_request_target` trigger now runs with no default permissions
No source-code or cryptographic changes
Evidence from the diff
The commit adds permissions: {} at the workflow level to all GitHub Actions YAML files, which removes the default GITHUB_TOKEN permissions for the workflow as a whole. It then adds job-level permissions: blocks granting the least privilege required: contents: read for most CI/test jobs, contents: write plus pull-requests: write for automated formatting and update jobs, issues: write for cargo-mutants, and actions: read for the semver label job. The manage-pr.yml workflow, which uses the dangerous pull_request_target trigger, is left with no job-level permissions shown in the diff, meaning it now runs with no token permissions by default. The fuzz/generate-files.sh generator script is also updated so future generated fuzz workflows inherit the same restrictions.
Changed components
.github/workflows/cron-daily-fuzz.yml.github/workflows/cron-daily-kani.yml.github/workflows/cron-weekly-cargo-mutants.yml.github/workflows/cron-weekly-rustfmt.yml.github/workflows/cron-weekly-update-cargo-semver-checks.yml.github/workflows/cron-weekly-update-nightly.yml.github/workflows/cron-weekly-update-stable.yml.github/workflows/gh-release.yml.github/workflows/manage-pr.yml.github/workflows/miri.yml.github/workflows/release.yml.github/workflows/rust.yml.github/workflows/semver-checks-pr-label.yml.github/workflows/semver-checks.yml.github/workflows/shellcheck.ymlfuzz/generate-files.shInspect captured patch +94 / −0
diff --git a/.github/workflows/cron-daily-fuzz.yml b/.github/workflows/cron-daily-fuzz.yml
index 24b268a5..b93ab804 100644
--- a/.github/workflows/cron-daily-fuzz.yml
+++ b/.github/workflows/cron-daily-fuzz.yml
@@ -7,11 +7,14 @@ on:
# - 6am CET
# - 4pm AEDT
- cron: '00 05 * * *'
+permissions: {}
jobs:
fuzz:
if: ${{ !github.event.act }}
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -78,6 +81,8 @@ jobs:
if: ${{ !github.event.act }}
needs: fuzz
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
diff --git a/.github/workflows/cron-daily-kani.yml b/.github/workflows/cron-daily-kani.yml
index e872532b..18191a5b 100644
--- a/.github/workflows/cron-daily-kani.yml
+++ b/.github/workflows/cron-daily-kani.yml
@@ -3,9 +3,12 @@ name: Kani CI
on:
schedule:
- cron: '59 23 * * *' # midnight every day.
+permissions: {}
jobs:
run-kani:
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
steps:
- name: 'Checkout your code.'
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
diff --git a/.github/workflows/cron-weekly-cargo-mutants.yml b/.github/workflows/cron-weekly-cargo-mutants.yml
index cdc67934..1b0a989f 100644
--- a/.github/workflows/cron-weekly-cargo-mutants.yml
+++ b/.github/workflows/cron-weekly-cargo-mutants.yml
@@ -3,9 +3,13 @@ on:
schedule:
- cron: "0 0 * * 0" # runs weekly on Sunday at 00:00
workflow_dispatch: # allows manual triggering
+permissions: {}
jobs:
cargo-mutants:
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
+ issues: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
diff --git a/.github/workflows/cron-weekly-rustfmt.yml b/.github/workflows/cron-weekly-rustfmt.yml
index 5160be64..81e751ba 100644
--- a/.github/workflows/cron-weekly-rustfmt.yml
+++ b/.github/workflows/cron-weekly-rustfmt.yml
@@ -3,10 +3,14 @@ on:
schedule:
- cron: "0 0 * * 0" # runs weekly on Sunday at 00:00
workflow_dispatch: # allows manual triggering
+permissions: {}
jobs:
format:
name: Nightly rustfmt
runs-on: ubuntu-24.04
+ permissions:
+ contents: write
+ pull-requests: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
@@ -28,3 +32,4 @@ jobs:
Automated nightly `rustfmt` changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action
commit-message: ${{ env.date }} automated rustfmt nightly
labels: rustfmt
+
diff --git a/.github/workflows/cron-weekly-update-cargo-semver-checks.yml b/.github/workflows/cron-weekly-update-cargo-semver-checks.yml
index 0bee1f2f..4f32e1d9 100644
--- a/.github/workflows/cron-weekly-update-cargo-semver-checks.yml
+++ b/.github/workflows/cron-weekly-update-cargo-semver-checks.yml
@@ -3,10 +3,14 @@ on:
schedule:
- cron: "0 0 * * 6" # runs every Saturday at 00:00
workflow_dispatch: # allows manual triggering
+permissions: {}
jobs:
format:
name: Update cargo-semver-checks
runs-on: ubuntu-24.04
+ permissions:
+ contents: write
+ pull-requests: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
diff --git a/.github/workflows/cron-weekly-update-nightly.yml b/.github/workflows/cron-weekly-update-nightly.yml
index ad893498..5363c666 100644
--- a/.github/workflows/cron-weekly-update-nightly.yml
+++ b/.github/workflows/cron-weekly-update-nightly.yml
@@ -3,10 +3,15 @@ on:
schedule:
- cron: "5 0 * * 6" # Saturday at 00:05
workflow_dispatch: # allows manual triggering
+permissions: {}
jobs:
format:
name: Update nightly rustc
runs-on: ubuntu-24.04
+ permissions:
+ contents: write
+ id-token: write
+ pull-requests: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
diff --git a/.github/workflows/cron-weekly-update-stable.yml b/.github/workflows/cron-weekly-update-stable.yml
index e406411f..4c2c3f14 100644
--- a/.github/workflows/cron-weekly-update-stable.yml
+++ b/.github/workflows/cron-weekly-update-stable.yml
@@ -3,10 +3,14 @@ on:
schedule:
- cron: "0 0 * * 5" # runs every Friday at 00:00 (generally rust releases on Thursday)
workflow_dispatch: # allows manual triggering
+permissions: {}
jobs:
format:
name: Update stable rustc
runs-on: ubuntu-24.04
+ permissions:
+ contents: write
+ pull-requests: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
diff --git a/.github/workflows/gh-release.yml b/.github/workflows/gh-release.yml
index 2c70ec0a..c8e33010 100644
--- a/.github/workflows/gh-release.yml
+++ b/.github/workflows/gh-release.yml
@@ -5,9 +5,13 @@ on:
tags:
- '*'
+permissions: {}
+
jobs:
build:
runs-on: ubuntu-24.04
+ permissions:
+ contents: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
diff --git a/.github/workflows/manage-pr.yml b/.github/workflows/manage-pr.yml
index c87685dd..4f8ae325 100644
--- a/.github/workflows/manage-pr.yml
+++ b/.github/workflows/manage-pr.yml
@@ -1,6 +1,7 @@
name: Manage PR
on:
- pull_request_target
+permissions: {}
jobs:
labeler:
diff --git a/.github/workflows/miri.yml b/.github/workflows/miri.yml
index b9238783..718bd0de 100644
--- a/.github/workflows/miri.yml
+++ b/.github/workflows/miri.yml
@@ -8,10 +8,14 @@ on: # yamllint disable-line rule:truthy
name: Miri
+permissions: {}
+
jobs:
Miri:
name: Miri
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
steps:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 78458669..4f8d40c5 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -8,11 +8,14 @@ on:
pull_request:
name: Release
+permissions: {}
jobs:
release:
name: Release - dry-run
runs-on: ubuntu-24.04
+ permissions:
+ contents: write
steps:
- name: Checkout Crate
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 43179b82..f76fcdff 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -8,9 +8,13 @@ on: # yamllint disable-line rule:truthy
name: Continuous integration
+permissions: {}
+
jobs:
Prepare:
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
outputs:
nightly_version: ${{ steps.read_toolchain.outputs.nightly_version }}
maintainer_tools_version: ${{ steps.read_toolchain.outputs.maintainer_tools_version }}
@@ -29,6 +33,8 @@ jobs:
name: Test - stable toolchain
needs: Prepare
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -56,6 +62,8 @@ jobs:
name: Test - nightly toolchain
needs: Prepare
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -85,6 +93,8 @@ jobs:
name: Test - MSRV toolchain
needs: Prepare
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -114,6 +124,8 @@ jobs:
name: Lint - nightly toolchain
needs: Prepare
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -145,6 +157,8 @@ jobs:
name: Docs - stable toolchain
needs: Prepare
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -172,6 +186,8 @@ jobs:
name: Docs - nightly toolchain
needs: Prepare
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -201,6 +217,8 @@ jobs:
name: Bench - nightly toolchain
needs: Prepare
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -229,6 +247,8 @@ jobs:
Arch32bit:
name: Test 32-bit version
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
steps:
- name: "Checkout repo"
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -249,6 +269,8 @@ jobs:
name: Cross test - stable toolchain
if: ${{ !github.event.act }}
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
steps:
- name: "Checkout repo"
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -267,6 +289,8 @@ jobs:
name: Embedded - nightly toolchain
needs: Prepare
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
env:
RUSTFLAGS: "-C link-arg=-Tlink.x"
CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER: "qemu-system-arm -cpu cortex-m3 -machine mps2-an385 -nographic -semihosting-config enable=on,target=native -kernel"
@@ -297,6 +321,8 @@ jobs:
name: ASAN - nightly toolchain
needs: Prepare
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -320,6 +346,8 @@ jobs:
WASM: # hashes crate only.
name: WASM - stable toolchain
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
# Note we do not use the recent lock file for wasm testing.
@@ -336,6 +364,8 @@ jobs:
Kani:
name: Kani codegen - stable toolchain
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
steps:
- name: "Checkout repo"
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -350,6 +380,8 @@ jobs:
needs: Prepare
name: API - nightly toolchain
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
@@ -373,6 +405,8 @@ jobs:
Policy:
name: Enforce repo policy - stable toolchain
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
steps:
@@ -388,6 +422,8 @@ jobs:
Re-exports:
name: Check re-exports - stable toolchain
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
steps:
diff --git a/.github/workflows/semver-checks-pr-label.yml b/.github/workflows/semver-checks-pr-label.yml
index 6506cdb8..a1538bf5 100644
--- a/.github/workflows/semver-checks-pr-label.yml
+++ b/.github/workflows/semver-checks-pr-label.yml
@@ -5,11 +5,14 @@ on: # yamllint disable-line rule:truthy
name: Check semver breaks - Label and Comment PR
+permissions: {}
+
jobs:
Download:
name: Download, Unzip and Add Labels/Comments
runs-on: ubuntu-24.04
permissions:
+ actions: read
contents: read
pull-requests: write
# only run if CI passes on the "Check semver breaks" workflow
diff --git a/.github/workflows/semver-checks.yml b/.github/workflows/semver-checks.yml
index 6434a8f1..2352b9ef 100644
--- a/.github/workflows/semver-checks.yml
+++ b/.github/workflows/semver-checks.yml
@@ -2,6 +2,7 @@ on: # yamllint disable-line rule:truthy
pull_request:
name: Check semver breaks
+permissions: {}
jobs:
PR:
@@ -9,6 +10,9 @@ jobs:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
+ permissions:
+ contents: read
+ pull-requests: write
steps:
- name: "Checkout repo"
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -49,6 +53,9 @@ jobs:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
+ permissions:
+ contents: read
+ pull-requests: write
steps:
- name: "Checkout repo"
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml
index ba4f9f03..84a84841 100644
--- a/.github/workflows/shellcheck.yml
+++ b/.github/workflows/shellcheck.yml
@@ -3,10 +3,13 @@ on:
pull_request:
branches:
- master
+permissions: {}
jobs:
shellcheck:
name: Shellcheck
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
diff --git a/fuzz/generate-files.sh b/fuzz/generate-files.sh
index 896fbd7d..2471c5ac 100755
--- a/fuzz/generate-files.sh
+++ b/fuzz/generate-files.sh
@@ -55,11 +55,14 @@ on:
# - 6am CET
# - 4pm AEDT
- cron: '00 05 * * *'
+permissions: {}
jobs:
fuzz:
if: \${{ !github.event.act }}
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
strategy:
fail-fast: false
matrix:
Why this scored 37/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.