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.

Why is this an issue?

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.

What is the potential impact?

Supply chain attacks

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.

Information disclosure

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.

System compromise

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.

How to fix it

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:

Code examples

Noncompliant code example

trigger: none

pool:
  vmImage: ubuntu-latest

steps:
- script: curl -sL https://example.com/install.sh | bash  # Noncompliant
  displayName: Install tool

Compliant solution

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

Resources

Documentation

Standards