Skip to content

JavaScript injection in CI workflow — unauthenticated issue tracker manipulation via crafted bug report

High
jNullj published GHSA-cf8p-vqfr-29v6 Jul 21, 2026

Package

actions shields (GitHub Actions)

Affected versions

>= af7b7f35971493d67a9c1cdfb496c3b11f8a6ffe

Patched versions

>= d925b814e9aae4a12c3359339d56b8fc73837c41

Description

Impact

The test-bug-run-badge.yml workflow evaluates attacker-controlled issue body content as JavaScript.
Any GitHub user can exfiltrate the workflow's GITHUB_TOKEN by opening a bug report issue, gaining the ability to manipulate all issues and pull requests in the repository, including the ability to add tags, like the release tags.

What an attacker achieves:

  • Exfiltrate GITHUB_TOKEN (scoped issues: write) via issue comment — renewable on every new issue
  • With issues: write, the attacker can:
    • Add or remove labels on any issue or pull request
    • Close, reopen, or lock any issue
    • Edit issue titles, bodies, assignees, and milestones
    • Post comments impersonating automated tooling
  • Attacker can add the release tag - if a maintainer miss the addition, a merge may end up as a release.
    • Pushes a new image to DockerHUb
    • Pushes a new image to GHCR

Taking a look at our recent release history there doesn't seem to be any sign of an unauthorized release.
This should not effect most users.
If you forked the shields repository and using our workflow in your own repository, please consider applying the fix to your own repository as well.

Patches

We decided to remove this workflow.
The workflow is removed at d925b81
This workflow was added at af7b7f3
All repo commits from af7b7f3 to 1f10232 are vulnerable.

If someone still wants to use this workflow, the reporter added a suggested patch which we confirmed to work

      - name: Add Comment to Issue
        uses: actions/github-script@v9
+       env:
+         BADGE_LINK: ${{ needs.extract-bug-badge-url.outputs.link }}
        with:
          script: |
+           const badgeLink = process.env.BADGE_LINK;
            const issueNumber = context.issue.number;
            const owner = context.repo.owner;
            const repo = context.repo.repo;
            const runId = context.runId;
            const jobUrl = `https://github.com/${owner}/${repo}/actions/runs/${runId}`;
            const issueComment = `
-             Badge tested using \`npm run badge ${{ needs.extract-bug-badge-url.outputs.link }}\`
+             Badge tested using \`npm run badge ${badgeLink}\`
              Output is available [here](${jobUrl})
            `;
            github.rest.issues.createComment({

Credit

Identified using VeeVee Agent, validated and disclosed by @EladMeged-Novee on behalf of Novee Security.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Changed
Confidentiality
Low
Integrity
Low
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N

CVE ID

No known CVE

Weaknesses

Improper Control of Generation of Code ('Code Injection')

The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment. Learn more on MITRE.

Credits