Executing a script downloaded from a remote source without verifying its integrity allows the remote content to run with the full privileges of the build environment.
In CI/CD pipelines, scripts are sometimes downloaded from remote sources and executed immediately without being saved to disk or verified first.
This can happen through piping (curl … | bash), process substitution (bash <(curl …)), command substitution (bash
-c "$(curl …)"), or eval. In all of these cases, the downloaded content is executed blindly with the full privileges of the build
environment.
If the remote host is compromised, the connection is intercepted, or the URL silently changes, an attacker gains arbitrary code execution inside the pipeline. Unverified remote scripts also make builds non-reproducible: the content at a URL can change between runs with no indication.
An attacker who gains control of the remote host, or who can intercept an unprotected connection, can inject malicious code directly into the build pipeline. This can be used to tamper with build artifacts before they are published, inject backdoors into packages or container images consumed by downstream systems, or pivot from the compromised build environment into production infrastructure.
Build environments in CI/CD pipelines typically have access to sensitive data such as repository secrets, API keys, deployment tokens, and cloud credentials. A malicious script executed in this context can exfiltrate those secrets to an attacker-controlled server or steal authentication tokens used for artifact publishing and cloud deployments.
A malicious script runs with the full privileges of the build process. It can modify the build system, install persistent backdoors on the runner, or alter source code and build configuration to affect future pipeline runs.
Instead of executing a remote script directly, download it to a local file first and verify its integrity before execution. This ensures the content matches what is expected and has not been tampered with.
Several methods can verify the integrity of a downloaded artifact:
sha256sum or sha512sum on Linux, or Get-FileHash on Windows/PowerShell..sig or .asc) using
gpg --verify with a trusted public key.Get-AuthenticodeSignature.trigger: none pool: vmImage: ubuntu-latest steps: - script: curl -sL https://example.com/install.sh | bash # Noncompliant displayName: Install tool
trigger: none
pool:
vmImage: ubuntu-latest
variables:
EXPECTED_HASH: 'a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4'
steps:
- script: |
curl -sL https://example.com/install.sh -o /tmp/install.sh
echo "$(EXPECTED_HASH) /tmp/install.sh" | sha256sum --check --status || { echo "Hash verification failed"; exit 1; }
bash /tmp/install.sh
displayName: Install tool