Introducing Tenki's code reviewer: deep, context-aware reviews that actually find bugs.Try it for Free
Security
Jul 2026

38% of Workflows Are Vulnerable to Pwn Requests

Eddie Wang
Eddie Wangengineering

Share Article:

Datadog published the companion piece to their 2026 State of DevSecOps report on June 2, and the headline stat is grim: 38% of organizations have at least one GitHub Actions workflow vulnerable to script injection or dangerous trigger misconfiguration. Zoom out further and two out of three organizations have at least one vulnerability in a workflow or action. These aren't theoretical risks. Three named attack campaigns exploited exactly these patterns in production over the past year.

The uncomfortable truth is that every one of these attack patterns was visible in the workflow YAML before the vulnerable code reached the default branch. A pre-merge review that understands GitHub Actions semantics would have flagged each of them. That's the gap this article covers: what the Datadog data shows, what each attack exploited, and where a review gate fits.

The Datadog numbers, in context

The Datadog Security Labs post separates GitHub Actions vulnerabilities into two categories: vulnerable workflow logic and vulnerable action supply chain. The original 2026 State of DevSecOps report covered the supply chain side. This companion post covers the workflow side, which the report didn't have room for.

The key findings:

  • 38% of organizations have a workflow vulnerable to script injection or dangerous trigger issues.
  • Two out of three organizations have at least one vulnerability in either a workflow or an action.
  • 71% of organizations never pin any of their GitHub Actions to a commit SHA, leaving them exposed to tag-swapping attacks.
  • Only 4% of organizations pin all public GitHub Actions to a specific version using commit hashes.

Those numbers matter because of where GitHub Actions sits in the development process. Workflows have direct access to source code, handle secrets and tokens, and automate deployments. A misconfigured workflow is a high-privilege entry point into the software supply chain.

Attack #1: s1ngularity and the pwn request

The s1ngularity attack targeted Nx by exploiting the pull_request_target trigger. This technique, known as a "pwn request," abuses the fact that pull_request_target grants elevated permissions (write access, secrets) while processing code from an external contributor's fork.

Quick background: the normal pull_request trigger prevents write permissions and secrets access by default. That's safe for CI on forks. But pull_request_target was created for cases where those elevated permissions are genuinely needed, like posting a comment on a PR from a fork. The entire security model assumes that pull_request_target workflows will only operate on trusted repository code and passive PR metadata. The moment a maintainer checks out and runs PR code inside a pull_request_target workflow, that external code executes with the repo's secrets.

GitHub released guidance on preventing pwn requests more than four years before s1ngularity exploited the pattern. The fix was documented. The vulnerable workflows merged anyway.

The detection pattern is straightforward: any workflow using pull_request_target that also checks out and executes code from the PR head ref is dangerous. If a review tool understands this pattern, it can flag it before the workflow file lands on main.

Attack #2: hackerbot-claw and script injection

The hackerbot-claw campaign was an AI-powered attack that targeted GitHub Actions workflows at scale. According to StepSecurity, it achieved remote code execution in more than half of the repositories it targeted. The technique was classic script injection: the attacker injected shell metacharacters through PR titles that were interpolated directly into run: steps.

Here's the vulnerable pattern. A workflow step that uses an inline expression to echo a PR title:

- name: Print PR Title
  run: echo "The title is: ${{ github.event.pull_request.title }}"

If an attacker names their PR "; rm -rf / #, the shell finishes the echo command at the semicolon, then executes the destructive command that follows. PR titles, branch names, issue comments, commit messages, and any other user-controlled field passed into a run: block via ${{ }} expression syntax is an injection vector.

The safe alternative is to use an intermediate environment variable or a JavaScript action that treats the value as data rather than code:

- name: Securely process title
  uses: ./.github/actions/my-js-action
  with:
    pr-title: ${{ github.event.pull_request.title }}

The injectable pattern is recognizable from static analysis of the YAML alone. Any ${{ github.event.* }} expression inside a run: step that references user-controlled input is a finding. A review tool doesn't need runtime context to flag it.

Attack #3: TeamPCP and the unpinned action supply chain

The TeamPCP campaign took a different approach. Attackers used compromised credentials to publish malicious versions of Trivy and KICS on GitHub, then forced version tags to point at the compromised release. Any workflow referencing @v1 or a similar mutable tag silently pulled and executed attacker-controlled code on the next run.

The defense is pinning actions to a full commit SHA instead of a mutable tag. The difference looks like this:

# Insecure: pinning to a tag
uses: thollander/actions-comment-pull-request@v2

# Secure: pinning to a commit SHA
uses: thollander/actions-comment-pull-request@b07c7f86be67002023e6cb13f57df3f21cdd3411

71% of organizations never pin any action to a hash. Only 4% pin all of them. That 96% gap is the population TeamPCP was fishing in. And pinning still won't protect against compromised transitive dependencies if those aren't also pinned, but it eliminates the most straightforward version of this attack.

When a PR adds or modifies a workflow file and references a third-party action by tag instead of SHA, that's a detectable finding at review time.

GitHub's roadmap is forward-looking. The exposure is now.

In March 2026, GitHub published a security roadmap for GitHub Actions that directly addresses these attack categories. The planned features are substantial:

  • Deterministic dependencies: a new dependencies: section in workflow YAML that locks all direct and transitive dependencies to commit SHAs. Targeted for general availability around September 2026.
  • Scoped secrets: credentials bound to the workflow that declared them, making the trust boundary between calling and called workflows explicit. Also targeted for September 2026.
  • Native egress firewall: outbound traffic monitoring and blocking on runners, expected toward the end of 2026.
  • Central policies: organization-level controls over which events can trigger workflows and who can initiate them.

These are good features. None of them exist today. The earliest general availability targets are three months out. The vulnerable workflows that have already merged aren't going to fix themselves, and new vulnerable workflows are being added in PRs right now.

The gap between today's exposure and the roadmap's delivery date is where a pre-merge review gate lives.

What a pre-merge review gate actually catches

The Datadog research covers two distinct failure modes, and both are detectable from PR diffs before merge.

Vulnerable workflow logic includes:

  • pull_request_target triggers that check out PR code (the s1ngularity pattern)
  • ${{ github.event.* }} expressions interpolated into run: steps (the hackerbot-claw pattern)
  • Overly broad GITHUB_TOKEN permissions that give write access where read-only would suffice

Vulnerable action supply chain includes:

  • Third-party actions referenced by mutable tag instead of commit SHA (the TeamPCP pattern)
  • New actions added to workflows without review of what they do or who maintains them

Every one of these patterns is visible in the .github/workflows/ diff in a pull request. They don't require runtime instrumentation, log analysis, or a separate scanning pipeline. They require someone (or something) to read the YAML and flag the patterns before the merge button gets clicked.

Tenki's code reviewer runs on every PR as a GitHub App and reviews the full diff, including workflow files. When a PR touches .github/workflows/, it can flag dangerous trigger configurations, injectable expression patterns, and unpinned third-party actions as review findings. The review happens before merge, at the point where fixing the issue is a YAML edit instead of an incident.

A checklist for your own workflows

If the 38% stat made you glance at your own .github/workflows/ directory, here's what to look for:

  1. Search for pull_request_target. If any workflow using this trigger also checks out and runs code from the PR head, it's vulnerable to pwn requests. Replace it with pull_request where possible, or restrict it to label-gated, metadata-only operations.
  2. Grep for ${{ github.event in run: blocks. Any user-controlled field (PR title, body, branch name, issue comment) interpolated into shell commands is injectable. Move the value to an environment variable or use a JavaScript action.
  3. Check if all third-party actions are pinned to commit SHAs. If you see @v2 or @main instead of a 40-character hash, you're exposed to the TeamPCP pattern. Enable Dependabot to keep hashes updated automatically.
  4. Audit GITHUB_TOKEN permissions. Default to read-only at the workflow level and grant write access only to specific jobs that need it.
  5. Treat workflow file changes like infrastructure changes. Require PR review for any commit touching .github/workflows/, ideally with a reviewer who understands Actions security semantics or a tool that does.

The 38% figure measures organizations with at least one vulnerable workflow. The fix for not joining that group is catching these patterns before they merge. GitHub's roadmap will help when it ships. In the meantime, the review gate is the control layer that's available right now.

Tags

#github-actions-security#supply-chain-security#devsecops#ci-cd-security#script-injection#pwn-request

Recommended for you

What's next in your stack.