Skip to main content
FieldValue
CategoryBEST-PRAC-1
SeverityHIGH
Auto-fix

What the check does

Flags any run: script (GitHub Actions and GitLab CI) that pipes a network fetch straight into an interpreter:
(curl|wget|iwr|invoke-webrequest) <anything-without-pipes> | [sudo] (sh|bash|zsh|ksh|dash|python3?|iex|node|perl|ruby)
This covers the common evasions of a naive curl | sh match: an intervening sudo, flags like bash -s, non-shell interpreters (python3, node), and PowerShell’s iwr … | iex.

Why it matters

curl https://example.com/install.sh | sh downloads a remote script and pipes it directly into the shell. Risks:
  • The remote host (or anyone in path) can serve different bytes on the next request.
  • A compromise of the distribution endpoint becomes immediate arbitrary execution on your runner — with whatever secrets and permissions the workflow has.
  • The script can detect it’s being piped (by reading file descriptors) and serve a benign version to inspectors and a malicious one to executors.

Vulnerable example

- run: curl -sSL https://get.example.com/install.sh | bash

Safe alternatives

1. Use a pinned official action. Most popular installers publish a setup-foo action — pin it to a commit SHA per CICD-SEC-3.
- uses: example/setup-foo@<sha> # v2
2. Download, verify, then run. Check a known checksum before execution:
- run: |
    curl -sSL https://get.example.com/install.sh -o install.sh
    echo "<known-sha256>  install.sh" | sha256sum -c -
    bash install.sh
3. Bake the installer into a container image you control, then runs-on: that image.

Why no auto-fix

There’s no safe automatic rewrite — the correct fix depends on whether an official action exists, what the expected checksum is, and what the surrounding flags do. This check is reported for human review.