Skip to content

feat(build): add actionlint and zizmor as required workflow security validation checks #352

@rezatnoMsirhC

Description

@rezatnoMsirhC

Summary

Add actionlint and zizmor as required workflow security validation checks on every PR that touches .github/workflows/**. This prevents recurrence of the script injection class of vulnerability (CWE-78) patched reactively in #350 / PR #351, and remediates the 8 remaining inputs.* interpolation instances across 3 workflow files.

Background

GitHub Actions evaluates ${{ expr }} template expressions server-side before the YAML is handed to the runner shell. When user-controlled values (branch names, PR titles, workflow inputs) are interpolated directly into run: blocks, an attacker can inject shell metacharacters to execute arbitrary commands in the runner context.

PR #351 (fixes #350) patched this in .github/workflows/create-release.yml by moving 4 expressions from inline run: text to step-level env: blocks. The same pattern (inputs.* directly in run:) remains in 3 other workflow files:

File Lines Expression Risk
security-deployment.yml 87, 88, 182, 183, 228 inputs.max-age-days, inputs.break-build, inputs.iac-types Medium (write access required)
application-matrix-builds.yml 172, 178 inputs.buildConfig, inputs.securityConfig (JSON blobs) High (JSON values embed shell metacharacters)
resource-provider-pwsh-tests.yml 78 inputs.test-results-output Medium (write access required)

Checkov (CKV_GHA_7) is configured in .checkov.yml with the github_actions framework active and no skips, but it does not produce line-level PR annotations and its CI invocation path is unconfirmed.

Acceptance Criteria

  • A new reusable workflow .github/workflows/workflow-lint.yml is added that runs actionlint v1.7.12 against all .github/workflows/*.yml files
  • The workflow is triggered on pull_request and push to main when paths under .github/workflows/** change
  • zizmor v1.23.1 is added to the same workflow to upload SARIF findings to the GitHub Security tab via github/codeql-action/upload-sarif
  • The 8 remaining inputs.* in run: patterns are remediated (moved to env: blocks) so the lint check passes without suppressions, OR each suppression is documented with justification
  • The workflow is called from pr-validation.yml as a required check

Implementation Notes

Recommended actionlint integration (binary install, no unverified third-party action):

- name: Install actionlint
  shell: bash
  run: |
    ACTIONLINT_VERSION="1.7.12"
    curl -sSfL \
      "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" \
      -o /tmp/actionlint.tar.gz
    tar -xzf /tmp/actionlint.tar.gz -C /tmp actionlint
    sudo mv /tmp/actionlint /usr/local/bin/
    rm /tmp/actionlint.tar.gz

- name: Run actionlint
  shell: bash
  run: actionlint -color .github/workflows/*.yml

zizmor SARIF integration:

- name: Run zizmor
  shell: bash
  run: zizmor --format sarif --output zizmor.sarif . || true

- name: Upload SARIF
  uses: github/codeql-action/upload-sarif@<pinned-sha>
  with:
    sarif_file: zizmor.sarif
    category: zizmor

Remediation pattern (same pattern as PR #351):

# Before (vulnerable)
run: |
  VALUE="${{ inputs.some-input }}"

# After (safe)
env:
  VALUE: ${{ inputs.some-input }}
run: |
  echo "$VALUE"

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsecuritySecurity-related changes or concerns

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions