GitHub Actions Security
Skylos can scan GitHub Actions workflow files as part of --danger.
This means the same CLI run that catches application security issues can also review CI/CD configuration in:
.github/workflows/*.yml.github/workflows/*.yamlaction.ymlaction.yaml
Use this when you want pull requests to flag workflow changes that affect tokens, secrets, runners, release jobs, containers, or third-party action code.
Run The Scanner
From the repository root:
skylos . --danger
For a normal PR gate, combine workflow security with secrets and quality checks:
skylos . --danger --secrets --quality --gate
For changed-code review:
skylos . --danger --secrets --quality --diff origin/main
Workflow findings appear in the same Security Issues output as application
security findings.
What Skylos Catches
Skylos focuses on CI/CD patterns that are high-signal in code review.
| Risk | Examples |
|---|---|
| Privileged triggers | pull_request_target, workflow_run |
| Broad token permissions | missing permissions, write-all, workflow-level write scopes |
| Mutable third-party code | unpinned uses: references and reusable workflows |
| Checkout credentials | actions/checkout without persist-credentials: false |
| Template injection | attacker-controlled GitHub contexts expanded in run, action inputs, or container options |
| Runner trust | self-hosted runners and dynamic runs-on expressions |
| Mutable containers | job containers, services, Docker actions, docker pull, and docker run without digest pinning |
| Secret exposure | secrets: inherit, toJSON(secrets), dynamic secret lookup, broad secret env scope |
| Release risk | OIDC jobs invoking repo-controlled build or release scripts |
| Artifact and package risk | lax artifact uploads, package installs that run lifecycle scripts, missing timeouts |
| AI agents in CI | claude-code-action, codex-action, run-gemini-cli, ai-inference or agent CLIs that untrusted issues, comments or fork pull requests can steer |
See Rules Reference for the full rule list.
Example Finding
name: CI
on:
pull_request_target:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: echo "${{ github.event.pull_request.title }}"
This workflow can produce findings for:
- privileged
pull_request_targetexecution - missing explicit token permissions
- unpinned action reference
- checkout credentials left available for later steps
- attacker-controlled pull-request title expanded directly in shell
Safer Baseline
For untrusted pull requests, keep the workflow unprivileged:
name: Skylos Security Gate
on:
pull_request:
branches: [main]
permissions:
contents: read
pull-requests: write
jobs:
skylos:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- uses: actions/setup-python@42375524d7b3f331cfa0bf3d4e21d0d3e1df3630
with:
python-version: "3.12"
- run: pip install skylos
- run: skylos . --danger --secrets --quality --gate
The SHA values above are examples. Pin actions to the full commit SHA you have reviewed.
AI Agents In Workflows
AI coding agents in GitHub Actions follow instructions in the text they read. On events that anyone can start, that text is attacker-written. Skylos reports the combination that makes this exploitable, and names the path:
name: Issue triage
on:
issues:
types: [opened]
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: "*"
claude_args: --allowedTools "Bash,Read,Write,Edit"
prompt: "Triage: ${{ github.event.issue.title }}"
SKY-D351 CRITICAL issues (anyone who can open an issue) → claude-code-action
(the prompt interpolates github.event.issue.title) with allowed_non_write_users: "*",
which lets any account past the action's write-access check; the agent has shell
commands (Bash in --allowedTools) and secrets ANTHROPIC_API_KEY; ...
SKY-D352 HIGH ...
SKY-D353 HIGH ...
| Rule | Reports |
|---|---|
SKY-D350 | No actor gate in front of an agent that has no built-in check (run-gemini-cli, claude-code-base-action, ai-inference, agent CLIs) |
SKY-D351 | The action's built-in write-access check widened with "*" |
SKY-D352 | Any-command shell access on an untrusted trigger |
SKY-D353 | Event text interpolated into the prompt |
SKY-D354 | An agent action or CLI version with a published advisory |
What Skylos checks before reporting:
- Who can start it. Event types that need triage access (
labeled,assigned) are trusted.if:conditions on the job, itsneedschain and the step are evaluated per event:author_associationof the triggering account in OWNER, MEMBER or COLLABORATOR, an exact actor, a same-repository pull request check, or an earlier collaborator-permission check all gate the agent. claude-code-action, codex-action and the opencode action check write access themselves unless that check is widened. - Whether attacker text reaches the agent. The action loads the triggering thread, the prompt or an earlier step passes event text, the agent has a tool that reads issues or pull requests, or the job checks out the pull request's code. A fixed prompt over the base branch is not reported.
- What the agent can do. Shell, tools that change things, read-only tools,
or none. Agents with no tools are not reported. Gemini CLI 0.39.1 and later
ignores workspace settings and turns off YOLO approval unless
GEMINI_CLI_TRUST_WORKSPACEis set, so those runs count as read-only. - What the job holds. Secrets, write scopes, undeclared token permissions
or
id-token: write.
A fixed environment: name is mentioned in the message rather than treated
as a gate: required reviewers are a repository setting the scan cannot see.
Release And Deploy Jobs
Release workflows deserve stricter review because they often have access to:
- package publishing tokens
- cloud OIDC federation
- repository write permissions
- production secrets
- signed artifact or provenance steps
Skylos flags release-like workflows that combine sensitive permissions with repo-controlled scripts or mutable state.
Example:
permissions:
contents: read
id-token: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- run: ./scripts/build.sh
- run: ./scripts/publish.sh
The scanner reports this because local build and release scripts become part of the OIDC trust boundary. A safer design separates build/test work from the credential-minting publish step.
Suppressions
Use suppressions only when the workflow risk is intentional and reviewed.
Inline suppressions work on the same line or the line above the finding:
# skylos: ignore[SKY-D292] internal action is pinned by organization policy
- uses: actions/checkout@v4
For repo-wide policy, use the normal Skylos configuration and suppression workflow described in Configuration.
Limitations
GitHub Actions scanning is static analysis. It does not execute workflows, resolve every dynamic expression, or audit remote action source code.
It is strongest for review-time guardrails:
- spotting dangerous workflow structure
- making token and secret scope visible
- catching mutable action/container references
- highlighting risky release automation
Use it alongside GitHub branch protection, environment protection rules, action pinning policy, and code-owner review for workflow changes.
Other CI Providers
Skylos runs in Jenkins, GitLab CI, Bitbucket Pipelines, Azure Pipelines,
CircleCI, Buildkite, and other CI systems as a pull request gate.
skylos cicd init sets it up for the CI your repository uses; see
Other CI Providers.
The workflow-configuration scanner on this page covers GitHub Actions. Skylos
also checks .gitlab-ci.yml (SKY-D314 to SKY-D323). It does not parse
Jenkinsfile, CircleCI, Bitbucket Pipelines, Azure Pipelines, or Buildkite
configuration for CI/CD misconfiguration rules.