SEC2-082: Firefox workflows keep the checkout credential in the working copy while running code the pull request controls #10
Labels
No labels
bug
documentation
enhancement
security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo-firefox#10
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-10-16 in a read-only security review of
postulo-firefoxatc9ee306, checked by a second, independent pass.Severity: Low · Category: Configuration · Reference: CWE-522 (Insufficiently Protected Credentials); CWE-829 (Inclusion of Functionality from Untrusted Control Sphere); OWASP A08:2021 (Software and Data Integrity Failures)
Location:
.forgejo/workflows/ci.yml:14-15(actions/checkout@v4with nopersist-credentials: false, thennpm ci).forgejo/workflows/release.yml:24-25(same)scripts/build.mjs:15-21, 34(clonespin.repositoryfromsource.jsonand executes itsscripts/build.mjs).forgejo/workflows/ci.yml:14-16(the model:persist-credentials: false)Issue
Both postulo-firefox workflows run on
pull_requestand start withactions/checkoutwrites the job's token into.git/configunlesspersist-credentials: falseis set; postulo-chromium's workflow sets it and this repository's does not. Everything after it
runs code the pull request chooses: the lifecycle scripts of whatever
package-lock.jsonthe PRcarries under
npm ci, andscripts/build.mjs, which readssource.jsonfrom the PR andgit clones and executes thescripts/build.mjsof that repository at that ref(
scripts/build.mjs:20-21, 34). A PR that changessource.json'srepositorytherefore runs arepository of its choosing in CI. That CI runs PR code is inherent; the credential left beside it
is not. Whether Forgejo hands a fork's
pull_requesta token with write scope is a server settingthat could not be checked from the repository, so the reach below is "likely"; the missing flag
is confirmed.
Impact
Someone who opens a pull request against postulo-firefox may be able to read the job's token from
the checkout and act on the repository with it (push to a branch, alter the release workflow); the
release job on a tag push is then only as trustworthy as that token's scope. Depends on the
Forgejo instance's token policy for forks.
Fix
In both workflows:
and have
scripts/build.mjsrefuse apin.repositoryother thanhttps://source.tiagoagueda.com/postulo/postulo-chromium.git, so a PR cannot point the buildelsewhere by editing one JSON line. (Action references stay on tags, as the core's
.forgejo/zizmor.ymlrecords for this Forgejo; apermissions:block is not added, since Forgejo16 ignores it.)
Done when both workflows carry
persist-credentials: false, a grep of.git/configaftercheckout in CI shows no
extraheader, and a test ofbuild.mjsrefuses asource.jsonnaminganother repository.
Related
#1 (closed), "Reproducible builds … and small hardening": its item 3 asked to update
upload-artifact@v3, which stays at v3 by a documented choice (ci.yml:26-30); it did notmention
persist-credentials.