Describe the bug
Combining reports of several related misbehaviors, because they have overlapping root causes and some interact with each other in various ways:
- 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].
- 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
- 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.
- 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.
- Severity mismatch: catalog.py:309 registers SKY-D295 as HIGH; the finding is emitted with severity="MEDIUM", potentially bypassing severity gates
- 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
Describe the bug
Combining reports of several related misbehaviors, because they have overlapping root causes and some interact with each other in various ways:
runs-on: [self-hosted, linux], but fails to trigger onruns-on: [linux, self-hosted].workflow_runthe 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 codeworkflow_runappears in a comment, branch name inbranches:, or thename:of the workflow itself. For example:fires
, but if the actual
workflow_runis absent it does not fire, so it is not firing on the comment itself, it is actually firing onworkflow_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:
fires no findings.
ignorewas introduced in the first place because SKY-D295 fires onos: [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.does not fire SKY-D290 at all
8. Textual references defeat line ignores: Combining several of the issues above,
fires SKY-D290 on both, but both are sourced to the comment and not the actual occurrence:
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