Rules / GL011
GL011 Download-and-execute pattern in script (curl | bash)
Severity: error
OWASP: CICD-SEC-3 – Dependency Chain Abuse
What glsec checks
glsec flags script lines that download content with curl or wget and pipe it directly into a shell interpreter, including via bash process substitution:
| Pattern | Example |
|---|---|
| Pipe to shell | curl URL | bash |
| Pipe to sh | wget -qO- URL | sh |
| Pipe to Python | curl URL | python3 |
| Pipe to Ruby/Perl/Node | curl URL | ruby |
| Process substitution | python3 <(curl URL) |
| Multi-stage pipe | curl URL | base64 -d | bash |
| Command substitution | bash -c "$(curl URL)" |
| Substitution piped to shell | echo "$(curl URL)" | bash |
| Inline base64 payload | echo "…" | base64 -d | bash |
| Download-then-execute | curl URL -o f.sh && bash f.sh |
| Redirect-then-execute | curl URL > f.sh; sh f.sh |
A line that also runs an integrity check (sha256sum, sha512sum, shasum, gpg --verify, cosign verify) is treated as verified and not flagged. Pipes or shell tokens that appear only inside a quoted string literal do not trigger.
Trigger example
setup:
script:
- curl -sSL https://install.example.com/setup.sh | bash
- wget -qO- https://raw.githubusercontent.com/org/repo/main/install.sh | sh
- python3 <(curl -s https://example.com/bootstrap.py)
- echo "$(curl -s https://example.com/payload)" | bash
- echo "ZWNobyBwd25lZAo=" | base64 -d | bash
- curl -fsSL https://example.com/install.sh -o install.sh && bash install.sh
- curl -fsSL https://example.com/payload.sh > install.sh; sh install.sh
Safe alternative
Download the script first, verify its checksum, then execute:
setup:
script:
- curl -sSLO https://install.example.com/setup.sh
- echo "a3b4c5d6… setup.sh" | sha256sum --check
- bash setup.sh
Or better: commit the script to the repository and reference it locally, removing the runtime network dependency entirely.
Why this matters
HTTPS provides transport-level security but no content integrity guarantee. If the script host is compromised, the pipeline will silently execute malicious code in the CI environment with access to all secrets, tokens, and build artifacts. Unlike a committed dependency, the executed code is unversioned and cannot be audited in pull request reviews or git history.
See also
GL083 covers the other half of this problem: a script line that opens a shell back to a remote host without downloading anything.
Enable the ShellCheck integration to surface additional shell issues in these script blocks.
Documentation for glsec 1.23.0. Source of this page · Rule implementation