Skip to content

[actions] Alternate actions/checkout paths suppress untrusted-checkout alerts #22213

Open

Description

@1sgtpepper

Description of the issue

actions/untrusted-checkout/critical does not report a privileged workflow that checks out an untrusted PR into a non-default path: and then executes a script or local action from that checkout. The actions/untrusted-checkout/high fallback is also suppressed, so neither query reports the workflow.

Minimal reproducer

on: pull_request_target

permissions:
  contents: write

jobs:
  execute:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          repository: ${{ github.event.pull_request.head.repo.full_name }}
          ref: ${{ github.event.pull_request.head.sha }}
          path: candidate
      - run: bash candidate/proof.sh

actions/checkout places path: candidate under $GITHUB_WORKSPACE, so this executes the same checked-out script relationship as a default checkout followed by bash proof.sh.

Reproduction

The complete reproducer is in public fork PR #1.

  • Latest-release fork CI: CodeQL Action 4.37.1, CLI 2.26.1, codeql/actions-queries 0.6.31
  • Current-main CI: queries compiled directly from github/codeql@14450f5bf38ea9a3ce2e0e45dcf51c0bbdd01af5

Both successful runs scanned all 11 workflow files and produced the same result matrix:

Case Result
Default checkout followed by bash proof.sh actions/untrusted-checkout/critical
Default checkout followed by uses: ./.github/actions/proof actions/untrusted-checkout/critical
Default checkout with quoted or $GITHUB_WORKSPACE script paths actions/untrusted-checkout/critical
path: candidate, ./candidate, or candidate/ followed by the corresponding script no critical or high alert
path: candidate followed by uses: ./candidate/.github/actions/proof no critical or high alert
Immutable checkout control no critical or high alert

The CI also executed harmless script and composite-action canaries through the tested paths before analysis.

Expected result

The alternate-path cases should be reported by actions/untrusted-checkout/critical, like their default-path controls. A path-representation mismatch should not suppress both the critical query and its high fallback.

Source-level cause

At current main:

Normalizing explicit actions/checkout paths at the checkout model, with regression tests for bare, dot-relative, trailing-slash, and local-action forms, appears to be the smallest fix.

Activity

  1. oscarsj commented on Jul 20, 2026

    @oscarsj
    Member

    Thanks for the detailed report and reproducer — this is very helpful.

    You’re right that the path: checkout variant under pull_request_target should still be considered in scope for untrusted-checkout detection when later steps execute scripts or local actions from that checkout. Based on your analysis, this looks like a path-normalization mismatch between checkout modeling and poisonable-step path modeling, which can suppress both critical and the high fallback.

    We’ve triaged this as a likely query-modeling gap and will investigate a fix in the checkout/path normalization logic, along with regression coverage for alternate path forms (bare, ./, trailing slash, and local-action references).

    To help us validate edge cases and prevent regressions, could you share:

    1. Whether you observed any difference across runner OS (ubuntu-latest vs Windows/macOS) or shell (bash, sh, pwsh).
    2. Additional path variants you tested (for example path: ./candidate, path: candidate/, nested paths like path: a/b, or quoted run commands).
    3. Whether equivalent behavior occurs when the workflow is triggered by workflow_run or other privileged trigger patterns (if you tested those).
    4. If you can provide the SARIF (or alert list) from one “expected critical but none reported” run and one default-path control run, that helps us confirm the exact suppression path quickly.

    Thanks again — the minimal reproducer and source-level pointers already provide a strong starting point.

  2. 1sgtpepper commented on Jul 21, 2026

    @1sgtpepper
    Author

    Thanks, Oscar. I added the requested coverage in PR #2.

    Bash/sh alternate paths remain undetected across Ubuntu and macOS, including nested paths and workflow_run. Pwsh reports high rather than critical. Both CI runs include SARIF and JSON artifacts: released queries and current main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ActionsAnalysis of GitHub Actions

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions