/commands/github-actions/actionlint
actionlint: lint GitHub Actions workflows before you push
verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · 1.7.12updated 2026-10-20
- tool
- GitHub Actions
- versions
- actionlint 1.7
- os
- any
GitHub only validates a workflow when it runs. actionlint, an open-source linter, checks workflow files locally: YAML structure, ${{ }} expressions and their types, references to undefined matrix or steps values, untrusted inputs used in run: scripts, deprecated workflow commands and actions too old for current runners. Run it in the repository root; it finds .github/workflows/*.yml by itself.
One file with four problems
mkdir -p .github/workflows
cat > .github/workflows/ci.yml <<'EOF'
name: CI
on: pull_request
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- id: v
run: echo "::set-output name=ver::1.0"
- run: echo "${{ steps.v.outputs.ver }} ${{ github.event.pull_request.title }}"
- run: echo ${{ matrix.node }}
- uses: actions/setup-node@v1
EOF
actionlint -version | head -1
actionlint -no-color .github/workflows/ci.ymlOutput · exit 1
1.7.12
.github/workflows/ci.yml:9:14: workflow command "set-output" was deprecated. use `echo "{name}={value}" >> $GITHUB_OUTPUT` instead: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions [deprecated-commands]
|
9 | run: echo "::set-output name=ver::1.0"
| ^~~~
.github/workflows/ci.yml:10:51: "github.event.pull_request.title" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details [expression]
|
10 | - run: echo "${{ steps.v.outputs.ver }} ${{ github.event.pull_request.title }}"
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.github/workflows/ci.yml:11:23: property "node" is not defined in object type {} [expression]
|
11 | - run: echo ${{ matrix.node }}
| ^~~~~~~~~~~
.github/workflows/ci.yml:12:15: the runner of "actions/setup-node@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue [action]
|
12 | - uses: actions/setup-node@v1
| ^~~~~~~~~~~~~~~~~~~~~Each finding has a rule name in brackets. [expression] on pull_request.title is a script injection risk: a PR title like "; curl … | sh; " would run in your job. Pass it through env: instead:
- run: echo "$TITLE"
env:
TITLE: ${{ github.event.pull_request.title }}Run it in CI
- name: actionlint
run: |
bash <(curl -fsSL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
./actionlint -colorWhen shellcheck is installed, actionlint also checks the shell code in run: blocks.
Sources
Related pages
cheat sheets · github-actionsGitHub Actions cheat sheet: triggers, jobs, matrix, outputs and cachingGitHub Actions cheat sheet: triggers, jobs and needs, matrix builds, if conditions, step and job outputs, secrets and env, caching, artifacts, contexts.changes · github-actionsGitHub Actions: from ::set-output and ::save-state to $GITHUB_OUTPUTThe ::set-output and ::save-state workflow commands are deprecated: in each step, append name=value lines to the $GITHUB_OUTPUT and $GITHUB_STATE files instead.config · github-actionsGitHub Actions concurrency: cancel-in-progress for older runsconcurrency with a group per workflow and branch plus cancel-in-progress: true cancels the older run when a new commit is pushed to the same branch or PR.