SUMMARY
The GitHub Actions script used to prepare NUT tarballs and update GitHub Checks statuses and PR comments about it was mis-structured in terms of mixing code running with higher privileges (single-use token generated with write permissions) and untrusted inputs (PR source branch).
This was proven insecure by research attached to this advisory: a malicious PR run from a fork could extract the GITHUB_TOKEN value. It could potentially be abused while it was valid (while the GHA job ran) to manipulate Git repository contents, commit checks/statuses, or issue/PR comments, according to permissions it was issued with.
Kudos to @avivdon and @Wang-Haimin for independent discoveries and similar analysis, and responsible reporting, and additionally to @avivdon for preparing a separate set of repositories to prove the problem and evaluate the fixes.
Remedy:
- The script was restructured into two workflows, one dealing only with metadata writes (and permissions to do so, the set of which was revised and reduced), and another focusing only on build and upload of the tarball artifacts. Sibling repositories were revised, and this fix was also applied to WMNut recipes.
- NUT: problem introduced between releases v2.8.4 and v2.8.5, fixed after v2.8.5 before v2.8.6.
- WMNut: problem both introduced and fixed after the most recent official release 0.72.
- The token involved is generated for each run, so there is nothing to revoke or treat as compromised if a token did leak earlier.
- Actual code history seems to have never been abused by this vector (regular development and code sync across maintainer workstations and CI systems did not expose any abnormalities like force-pushes or unexpected advancement of the
master branch).
- There is nothing to fix for consumers of the NUT code base (packagers, etc.) regarding this issue. However if there are any forks including flawed code - their branches treated by GitHub as "default" or "base" (used for reference GHA implementations) should be updated with similar restructuring of
.github/workflows/01-make-dist*.yml scripts.
Follow-ups on the side:
- A GitHub backed facility for responsible reporting of suspected vulnerabilities was enabled
- A
SECURITY.md policy was published
- Dependabot enabled to keep GHA action versions up to date
INITIAL POST
Hello Network UPS Tools maintainers,
I would like to report a potential GitHub Actions CI/CD security issue affecting networkupstools/nut.
I did not access secrets, exfiltrate tokens, push changes, modify repository state, or perform destructive testing. This report is based on static verification of the current workflow structure.
Summary
Affected workflow:
.github/workflows/01-make-dist.yml
Checked commit:
db633d1bdf2ab36eb28343ae91bb0775ceaa1919
The workflow uses pull_request_target, grants write-capable permissions, checks out the pull request head SHA, and then executes scripts and build targets from the checked-out repository. This is a classic Pwn Request pattern.
Technical details
The workflow declares write-capable permissions:
checks: write
contents: write
issues: write
pull-requests: write
For pull request events, the checkout ref resolves to the PR head SHA:
github.event.pull_request.head.sha
The workflow then executes code from that checkout, including:
bash -x ./tools/gitlog2version.sh
./autogen.sh
./configure
make dist
make distcheck
make distcheck-completeness
make dist-docs
Because these files and build targets come from the PR checkout, a fork PR author may influence code executed in the pull_request_target workflow context.
Although persist-credentials: false is useful hardening for checkout credentials, it does not prevent execution of PR-controlled code in the privileged job. The same job still has write-capable workflow permissions and later uses GITHUB_TOKEN for GitHub API operations such as PR comments and check-run updates.
Impact
If exploited, a malicious pull request may execute code in a privileged workflow context.
Potential impact includes:
- misuse or exposure of a write-capable
GITHUB_TOKEN;
- modification of check-run status or PR/issue metadata;
- potential repository write impact through
contents: write;
- manipulation of generated distribution artifacts;
- misleading PR comments or build artifact links;
- broader supply-chain impact if generated artifacts are consumed by users or downstream automation.
Suggested remediation
Recommended fixes:
-
Do not checkout and execute PR head code in a pull_request_target workflow.
-
For untrusted PRs, use pull_request instead of pull_request_target, with no repository secrets and read-only permissions.
-
If pull_request_target is required, checkout only trusted base-branch code before running scripts.
-
Add a fork-origin rejection before privileged execution:
if: github.event.pull_request.head.repo.full_name == github.repository
-
Alternatively require a maintainer-applied trusted label or OWNER/MEMBER/COLLABORATOR actor check before running the privileged build.
-
Split the workflow:
untrusted PR build:
- pull_request
- no write token
- no secrets
- no distribution publication
trusted distribution build:
- same-repository branch or maintainer-approved only
- write token only after trust is established
-
Keep persist-credentials: false, but do not rely on it as the primary mitigation because it does not stop PR-controlled code execution.
-
Consider rotating tokens or reviewing recent workflow runs if untrusted fork PRs may previously have reached this workflow path.
SUMMARY
The GitHub Actions script used to prepare NUT tarballs and update GitHub Checks statuses and PR comments about it was mis-structured in terms of mixing code running with higher privileges (single-use token generated with write permissions) and untrusted inputs (PR source branch).
This was proven insecure by research attached to this advisory: a malicious PR run from a fork could extract the
GITHUB_TOKENvalue. It could potentially be abused while it was valid (while the GHA job ran) to manipulate Git repository contents, commit checks/statuses, or issue/PR comments, according to permissions it was issued with.Kudos to @avivdon and @Wang-Haimin for independent discoveries and similar analysis, and responsible reporting, and additionally to @avivdon for preparing a separate set of repositories to prove the problem and evaluate the fixes.
Remedy:
masterbranch)..github/workflows/01-make-dist*.ymlscripts.Follow-ups on the side:
SECURITY.mdpolicy was publishedINITIAL POST
Hello Network UPS Tools maintainers,
I would like to report a potential GitHub Actions CI/CD security issue affecting
networkupstools/nut.I did not access secrets, exfiltrate tokens, push changes, modify repository state, or perform destructive testing. This report is based on static verification of the current workflow structure.
Summary
Affected workflow:
Checked commit:
The workflow uses
pull_request_target, grants write-capable permissions, checks out the pull request head SHA, and then executes scripts and build targets from the checked-out repository. This is a classic Pwn Request pattern.Technical details
The workflow declares write-capable permissions:
For pull request events, the checkout ref resolves to the PR head SHA:
The workflow then executes code from that checkout, including:
Because these files and build targets come from the PR checkout, a fork PR author may influence code executed in the
pull_request_targetworkflow context.Although
persist-credentials: falseis useful hardening for checkout credentials, it does not prevent execution of PR-controlled code in the privileged job. The same job still has write-capable workflow permissions and later usesGITHUB_TOKENfor GitHub API operations such as PR comments and check-run updates.Impact
If exploited, a malicious pull request may execute code in a privileged workflow context.
Potential impact includes:
GITHUB_TOKEN;contents: write;Suggested remediation
Recommended fixes:
Do not checkout and execute PR head code in a
pull_request_targetworkflow.For untrusted PRs, use
pull_requestinstead ofpull_request_target, with no repository secrets and read-only permissions.If
pull_request_targetis required, checkout only trusted base-branch code before running scripts.Add a fork-origin rejection before privileged execution:
Alternatively require a maintainer-applied trusted label or OWNER/MEMBER/COLLABORATOR actor check before running the privileged build.
Split the workflow:
Keep
persist-credentials: false, but do not rely on it as the primary mitigation because it does not stop PR-controlled code execution.Consider rotating tokens or reviewing recent workflow runs if untrusted fork PRs may previously have reached this workflow path.