Harden CI/CD workflow token permissions (OpenSSF Scorecard Token-Permissions: 0)
@anshul23102 is already working on this.
Since Aug 2, 2026.
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 1.2k
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 16
Description
Summary
.github/workflows/ci_cd.yml does not declare a top-level permissions: block, and 8 of its 11 jobs declare no permissions: of their own. Those jobs run with the repository's default GITHUB_TOKEN scope rather than an explicit least-privilege scope.
OpenSSF Scorecard currently reports Token-Permissions: 0 for this repository (overall score 6.2, scan dated 2026-07-27).
Current state
| Job | Declared permissions |
|---|---|
pre-commit |
none |
code-ql |
security-events: write |
run-tests |
none |
build-package |
none |
test-build-package |
none |
test-docker-image |
none |
test-docker-image-build |
none |
publish-nettacker-dev-to-docker-registry |
none |
publish-nettacker-latest-to-docker-registry |
none |
publish-to-test-pypi |
contents: read, id-token: write |
publish-to-pypi |
contents: read, id-token: write |
The two PyPI publishing jobs already follow least privilege. The pattern was simply never extended to the rest of the file.
Why this is worth fixing
The practical impact depends on the organisation and repository default token setting, which is not visible externally, so this is defence in depth rather than a directly exploitable issue. Two things make it worth doing anyway:
- Two of the unscoped jobs (
publish-nettacker-dev-to-docker-registryandpublish-nettacker-latest-to-docker-registry) handleDOCKER_HUB_ACCESS_TOKENand pushowasp/nettacker:latest. These are the jobs where a broadly scoped ambient token is least desirable. - An explicit
permissions: {}default means any future job added to this workflow starts from zero rather than inheriting whatever the repository default happens to be at that time.
Proposed change
- Add
permissions: {}at the workflow level as a deny-by-default. - Add
permissions: contents: readto the eight jobs that currently declare none. - Add the missing
contents: readtocode-qlalongside its existingsecurity-events: write.
No job gains a permission it does not already have in practice, and no job logic changes. The diff is additive: 19 added lines, 0 removed.
Verification
- Workflow still parses;
check-yamlfrom the existing pre-commit config passes. - All 11 jobs end up with an explicit, minimal scope.
- Only
code-ql(security-events: write) and the two PyPI jobs (id-token: write) retain any write scope, which they require.
Note on the rest of the Scorecard report
Scorecard also reports Dangerous-Workflow: 0, but that scan predates ca200a1 (2026-08-01), which migrated the PR check to a SHA-pinned action with scoped permissions. That finding appears to be already resolved and should clear on the next scan. This issue is only about Token-Permissions.
I would like to work on this. @securestep9 could you assign it to me? I understand PRs are auto-closed without an assigned issue reference.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.