From ef09b88f3eacdbec6ce135a7c9a193a6849545c1 Mon Sep 17 00:00:00 2001 From: Michal Dorner Date: Wed, 5 Aug 2026 13:45:25 +0200 Subject: [PATCH] Document safe handling of file list outputs in workflows (#326) Recommend passing *_files values through env: instead of interpolating them directly into run: scripts, and update README examples and CI workflows to follow that pattern. Credits: https://github.com/tjswlsgg --- .github/workflows/pull-request-verification.yml | 16 ++++++++++++---- README.md | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pull-request-verification.yml b/.github/workflows/pull-request-verification.yml index 13fe10d..e8b7555 100644 --- a/.github/workflows/pull-request-verification.yml +++ b/.github/workflows/pull-request-verification.yml @@ -193,7 +193,9 @@ jobs: excludesOnly: - '!**/*.md' - name: Print 'mobile_files' - run: echo ${{steps.filter.outputs.mobile_files}} + env: + MOBILE_FILES: ${{ steps.filter.outputs.mobile_files }} + run: echo "$MOBILE_FILES" - name: filter-test if: | steps.filter.outputs.mobile != 'true' @@ -227,11 +229,17 @@ jobs: any: - added|deleted|modified: "*" - name: Print 'added_files' - run: echo ${{steps.filter.outputs.added_files}} + env: + ADDED_FILES: ${{ steps.filter.outputs.added_files }} + run: echo "$ADDED_FILES" - name: Print 'modified_files' - run: echo ${{steps.filter.outputs.modified_files}} + env: + MODIFIED_FILES: ${{ steps.filter.outputs.modified_files }} + run: echo "$MODIFIED_FILES" - name: Print 'deleted_files' - run: echo ${{steps.filter.outputs.deleted_files}} + env: + DELETED_FILES: ${{ steps.filter.outputs.deleted_files }} + run: echo "$DELETED_FILES" - name: filter-test if: | steps.filter.outputs.added != 'true' diff --git a/README.md b/README.md index 333f848..b675fd5 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,10 @@ For more scenarios see [examples](#examples) section. ## Notes +- **Security:** `${FILTER_NAME}_files` outputs contain filenames that may be attacker-influenced on pull requests. + Do not interpolate them directly into a `run:` script with `${{ ... }}`. + Pass the value through `env:` and reference the variable from the shell instead. + See [Custom processing of changed files](#custom-processing-of-changed-files). - Paths expressions are evaluated using [picomatch](https://github.com/micromatch/picomatch) library. Documentation for path expression format can be found on the project GitHub page. - Picomatch [dot](https://github.com/micromatch/picomatch#options) option is set to true. @@ -205,7 +209,7 @@ For more information, see [CHANGELOG](https://github.com/dorny/paths-filter/blob - `'true'` - if **any** changed file matches **at least one** of the filter's rules and **none** of its negated rules - `'false'` - if **no** changed file matches **at least one** of the filter's rules and **none** of its negated rules - Each filter sets an output variable with the name `${FILTER_NAME}_count` to the count of matching files. -- If enabled, for each filter it sets an output variable with the name `${FILTER_NAME}_files`. It will contain a list of all files matching the filter. +- If enabled, for each filter it sets an output variable with the name `${FILTER_NAME}_files`. It will contain a list of all files matching the filter. Treat these values as untrusted when filenames can come from pull requests. - `changes` - JSON array with names of all filters matching any of the changed files. ## Examples @@ -589,9 +593,13 @@ jobs: - added|modified: '*.md' - name: Lint Markdown if: ${{ steps.filter.outputs.markdown == 'true' }} - run: npx textlint ${{ steps.filter.outputs.markdown_files }} + env: + MARKDOWN_FILES: ${{ steps.filter.outputs.markdown_files }} + run: npx textlint $MARKDOWN_FILES ``` +When passing file lists to shell commands, use `env:` as shown above. Do not write `${{ steps.filter.outputs.markdown_files }}` directly inside the `run:` script. +
@@ -617,6 +625,8 @@ jobs: files: ${{ steps.filter.outputs.changed_files }} ``` +The `json` and `csv` formats are intended as structured data for scripts, programs, or other actions. Passing them to an action input as above is fine. Do not interpolate `json` or `csv` outputs directly into a `run:` script. +
## See also