Skip to content

SKY D290 and SKY295 misbehavior #791

Description

@mcdigman

Describe the bug
Combining reports of several related misbehaviors, because they have overlapping root causes and some interact with each other in various ways:

  1. False negative: SKY-D295 is order dependent; it correctly triggers on runs-on: [self-hosted, linux], but fails to trigger on runs-on: [linux, self-hosted].
  2. Incorrect line assignment: SKY-D290 flags the string workflow_run the first time it occurs in the file, even if it is in a comment, like # workflow_run is not dangerous here because it runs only from the default branch and checks out no attacker-controlled code
  3. Textual references defeat line ignores: An ignore for SKY-D290 is defeated if the string workflow_run appears in a comment, branch name in branches:, or the name: of the workflow itself. For example:
on:
  # SKY-D290 flags workflow_run because it is the usual way a privileged job
  # ends up running attacker-influenced code. That shape is absent here: the
  # job checks out nothing and executes no pull request code.
  # skylos: ignore[SKY-D290] privileged job never executes PR-controlled code
  workflow_run:
    workflows: ["Liveness Primer"]
    types: [completed]

fires

File: /Users/mcdigman/Claude/Projects/skylos/reproductions/skylos_d290_inline_ignore_line_anchor/.github/workflows/comment_names_trigger.yml:4
Name: github-actions-dangerous-trigger


       2 | 
       3 | on:
>>>    4 |   # SKY-D290 flags workflow_run because it is the usual way a privileged job
       5 |   # ends up running attacker-influenced code. That shape is absent here: the
       6 |   # job checks out nothing and executes no pull request code.
       7 |   # skylos: ignore[SKY-D290] privileged job never executes PR-controlled code
       8 |   workflow_run:

, but if the actual workflow_run is absent it does not fire, so it is not firing on the comment itself, it is actually firing on workflow_run: but with the incorrect line assignment bug from 2.
4. Line ignore creep: Line ignores for a noisy case of SKY-D295 ignore SKY-D295 for the entire file, which could mask an actual later addition of a genuinely self-hosted job:

  fixed-hosted-matrix:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
    # skylos: ignore[SKY-D295] matrix contains only GitHub-hosted labels
    runs-on: ${{ matrix.os }}
    steps:
      - run: echo "GitHub-hosted"

  genuinely-self-hosted:
    runs-on: self-hosted
    steps:
      - run: echo "Self-hosted"

fires no findings.

  1. Arguable false positive: Related to 4., the ignore was introduced in the first place because SKY-D295 fires on os: [ubuntu-latest, windows-latest, macos-latest], which is not actually self hosted, creating a 'boy who cried wolf effect'. Maintainer's call whether this is actually a false positive or not.
  2. Severity mismatch: catalog.py:309 registers SKY-D295 as HIGH; the finding is emitted with severity="MEDIUM", potentially bypassing severity gates
  3. Line ignore creep: Also happens for SKY-D290, but it is worse:
  # skylos: ignore[SKY-D290] a workflow_run is safe here, a pull_request_target would be dangerous
  workflow_run:
  pull_request_target:
    types: [opened]

does not fire SKY-D290 at all
8. Textual references defeat line ignores: Combining several of the issues above,

  # a workflow_run is safe here, a pull_request_target would be dangerous
  # skylos: ignore[SKY-D290] chained trigger runs no PR code
  workflow_run:
  pull_request_target:
    types: [opened]

fires SKY-D290 on both, but both are sourced to the comment and not the actual occurrence:

    █  HIGH  SKY-D290  Workflow uses pull_request_target; avoid running untrusted PR content with a privileged token.
      Security  .github/workflows/two_triggers_defeated.yml:4
      # a workflow_run is safe here, a pull_request_target would be dangerous

    █  HIGH  SKY-D290  Workflow uses workflow_run; avoid chaining privileged workflow execution from potentially attacker-influenced workflows.
      Security  .github/workflows/two_triggers_defeated.yml:4
      # a workflow_run is safe here, a pull_request_target would be dangerous

To Reproduce
Reproducing simulated workflows attached, in addition to the code examples above.

skylos_d290_inline_ignore_line_anchor.zip
skylos_d295_matrix_ignore_line_anchor.zip

Environment

  • Python version: 3.14.6
  • Skylos version: skylos 4.35.0

Activity

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

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions