OWASP / OWASP/Nettacker

Harden CI/CD workflow token permissions (OpenSSF Scorecard Token-Permissions: 0)

Open
#1,645 2 comments 1 reaction 1 assignee View on GitHub

@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:

  1. Two of the unscoped jobs (publish-nettacker-dev-to-docker-registry and publish-nettacker-latest-to-docker-registry) handle DOCKER_HUB_ACCESS_TOKEN and push owasp/nettacker:latest. These are the jobs where a broadly scoped ambient token is least desirable.
  2. 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: read to the eight jobs that currently declare none.
  • Add the missing contents: read to code-ql alongside its existing security-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-yaml from 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.