For AI agents: A markdown version of this page is available at https://docs.datadoghq.com/security/code_security/iac_security/iac_rules/cicd/github/unsound_conditions.md. A documentation index is available at /llms.txt.
This product is not supported for your selected Datadog site. ().

Metadata

Id: d4e5f6a7-b8c9-40d1-e2f3-a4b5c6d7e8f9

Cloud Provider: GitHub

Platform: CICD

Severity: High

Category: Build Process

Learn More

Description

Conditions that mix fenced GitHub Actions expressions (${{ ... }}) with YAML multiline block scalars (| or >) can evaluate incorrectly. The block scalar often adds trailing newlines, turning the expanded value into a non-empty string that GitHub Actions treats as truthy. This can cause conditions that should be false to always pass, allowing jobs or steps to run unintentionally. This check inspects the if property on jobs, steps, and reusable workflow calls. It flags cases where the if value contains a fenced expression and the overall scalar includes extra leading or trailing content, indicating that block style added whitespace or newlines. Remediate by using stripped block scalar styles (|- or >-) to remove trailing newlines, or by using a plain inline expression such as if: ${{ ... }}, so the fenced expression is evaluated as an expression rather than as a non-empty string.

Secure examples:

# Stripped literal block scalar removes trailing newline
if: |-
  ${{ github.event_name == 'push' }}
# Inline fenced expression (single line)
if: ${{ github.event_name == 'push' }}

Compliant Code Examples

name: Sound Conditions
on: push

jobs:
  # Case 1: Job-level with plain scalar (no block style)
  job_with_sound_condition:
    runs-on: ubuntu-latest
    if: ${{ github.event_name == 'pull_request' }}
    steps:
      - run: echo "This is sound"

  # Case 2: Properly fenced conditions
  test_sound_conditions:
    runs-on: ubuntu-latest
    steps:
      - name: Plain scalar condition
        if: ${{ github.event_name == 'push' }}
        run: echo "This condition is sound"

      # Case 3: Stripped literal block scalar (|- removes trailing newlines)
      - name: Stripped literal block scalar
        if: |-
          ${{ github.ref == 'refs/heads/main' }}
        run: echo "This is also sound"

      # Case 4: Stripped folded block scalar (>- removes trailing newlines)
      - name: Stripped folded block scalar
        if: >-
          ${{ github.actor != 'dependabot' }}
        run: echo "This is sound too"

      # Case 5: Bare expression without quotes (GitHub Actions evaluates this correctly)
      - name: Bare expression
        if: github.event_name == 'push'
        run: echo "No fencing, sound"

      # Case 6: Complex condition without excessive whitespace
      - name: Complex condition
        if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
        run: echo "Complex but sound"

Non-Compliant Code Examples

name: Composite action with unsound conditions
description: Composite action whose step conditions use YAML block scalars
runs:
  using: composite
  steps:
    - name: Unsound literal block
      if: |
        ${{ inputs.deploy == 'true' }}
      shell: bash
      run: echo "This will always run!"
name: Unsound Conditions
on: push

jobs:
  # Case 1: Job-level condition with literal block scalar
  job_with_unsound_condition:
    runs-on: ubuntu-latest
    if: |
      ${{ github.event_name == 'pull_request' }}
    steps:
      - run: echo "This will always run!"

  # Case 2: Step-level literal block scalar
  test_literal_block:
    runs-on: ubuntu-latest
    steps:
      - name: Unsound literal block
        if: |
          ${{ github.event_name == 'pull_request' }}
        run: echo "This will always run!"

      # Case 3: Folded block scalar
      - name: Unsound folded block
        if: >
          ${{ false }}
        run: echo "This will also always run!"

      # Case 4: Multiple spaces (excessive whitespace)
      - name: Excessive leading spaces
        if: "  ${{ github.ref == 'refs/heads/main' }}"
        run: echo "Has leading spaces"

      # Case 5: Tabs
      - name: Tab character
        if: "	${{ true }}"
        run: echo "Has tab character"

      # Case 6: Trailing spaces
      - name: Excessive trailing spaces
        if: "${{ github.actor == 'dependabot' }}  "
        run: echo "Has trailing spaces"

      # Case 7: Single space
      - name: Single space padding
        if: " ${{ true }} "
        run: echo "Single space is not fine"