Environment Variable Injection Rule (Medium) Overview #
This rule detects environment variable injection vulnerabilities when untrusted input is written to $GITHUB_ENV within normal workflow contexts. While these workflows have limited permissions compared to privileged contexts, environment variable injection can still lead to security issues and unexpected behavior.
Key Features: #
- Normal Trigger Detection: Identifies patterns in
pull_request,push,schedule, and other standard triggers - GITHUB_ENV Write Detection: Analyzes scripts that write to
$GITHUB_ENVfile - Auto-fix Support: Automatically sanitizes inputs using
tr -d '\n'to prevent newline injection - Developer-Friendly: Helps maintain secure coding practices even in lower-risk contexts
Security Impact #
Severity: Medium (5/10)
Environment variable injection in normal workflows represents a medium-severity vulnerability:
- Workflow Logic Manipulation: Attackers can alter workflow behavior through environment pollution
- Data Integrity Issues: Injected variables can corrupt build outputs or test results
- Defense-in-Depth: Preventing medium-risk patterns stops privilege escalation paths
- Best Practice Enforcement: Maintains security hygiene across all workflows
While normal workflows lack write permissions and secret access, environment variable injection can still:
- Interfere with CI/CD logic: Modified environment variables can skip tests or alter build configurations
- Create false positives/negatives: Test results can be manipulated
- Enable chaining attacks: If workflows later gain privileges, existing vulnerabilities become exploitable
This vulnerability is classified as CWE-77: Improper Neutralization of Special Elements used in a Command (‘Command Injection’) and CWE-20: Improper Input Validation.
Normal Workflow Triggers #
The following triggers are considered normal (non-privileged) workflows:
pull_request: Runs with read-only permissions for external PRspush: Triggered by repository pushesschedule: Runs on a cron scheduleworkflow_dispatch: Manually triggered workflowsmerge_group: Triggered by merge queue events
Example Vulnerable Workflow #
Consider this workflow that writes PR data to $GITHUB_ENV:
name: CI Build
on:
pull_request: # Normal trigger with limited permissions
types: [opened, synchronize]
jobs:
build:
runs-on: ubuntu-latest
steps:
# MEDIUM VULNERABILITY: Untrusted input written to GITHUB_ENV
- name: Set build variables
run: |
echo "PR_TITLE=${{ github.event.pull_request.title }}" >> "$GITHUB_ENV"
echo "PR_BRANCH=${{ github.event.pull_request.head.ref }}" >> "$GITHUB_ENV"
- name: Build project
run: |
echo "Building: $PR_TITLE from $PR_BRANCH"
npm run build
# Environment variables affect build process
Attack Scenario #
How Environment Variable Injection Works in Normal Workflows:
Attacker Creates Malicious PR: Opens a PR with a crafted title:
Title: Fix typo NODE_OPTIONS=--require=/tmp/malicious.js CI=falseWorkflow Triggers:
pull_requestruns with limited permissionsVariables Injected: The malicious input writes multiple environment variables:
# Attacker's input creates: PR_TITLE=Fix typo NODE_OPTIONS=--require=/tmp/malicious.js CI=falseBuild Process Affected: Subsequent steps run with altered environment:
- name: Run tests # Now running with CI=false run: | npm test # NODE_OPTIONS affects Node.js executionImpact: While limited in scope, this can:
- Skip test suites (via
CI=false) - Alter build configurations
- Create misleading CI results
- Interfere with quality gates
- Skip test suites (via
What Makes This Medium Risk #
Normal workflows with environment variable injection are medium risk because:
- Limited Permissions: No write access to repository or access to secrets
- Read-Only Context: Cannot directly modify code or configuration
- Isolated Impact: Effects are contained within the workflow run
- Defense-in-Depth: Prevents escalation if workflow gains privileges later
However, it’s still a security issue because:
- Workflow logic can be manipulated
- CI/CD decisions may be based on compromised data
- Creates technical debt that could become critical if workflow permissions change
Safe Pattern (Using Environment Variables with Sanitization) #
The recommended approach is to sanitize input by removing newlines:
name: CI Build (Safe)
on:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
# SAFE: Sanitize input before writing to GITHUB_ENV
- name: Set build variables safely
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BRANCH: ${{ github.event.pull_request.head.ref }}
run: |
# Remove newlines to prevent injection
echo "PR_TITLE=$(echo "$PR_TITLE" | tr -d '\n')" >> "$GITHUB_ENV"
echo "PR_BRANCH=$(echo "$PR_BRANCH" | tr -d '\n')" >> "$GITHUB_ENV"
- name: Build project
run: |
echo "Building: $PR_TITLE from $PR_BRANCH"
npm run build
Alternative: Avoid GITHUB_ENV Entirely #
For read-only workflows, consider using environment variables directly:
- name: Build project
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BRANCH: ${{ github.event.pull_request.head.ref }}
run: |
echo "Building: $PR_TITLE from $PR_BRANCH"
npm run build
Auto-Fix Example #
sisakulint can automatically fix this vulnerability:
Before (Vulnerable):
- name: Set variables
run: |
echo "TITLE=${{ github.event.pull_request.title }}" >> "$GITHUB_ENV"
After Auto-Fix (Safe):
- name: Set variables
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
echo "TITLE=$(echo "$PR_TITLE" | tr -d '\n')" >> "$GITHUB_ENV"
Detection Details #
The rule detects:
Direct writes to $GITHUB_ENV using various formats:
>> $GITHUB_ENV>> "$GITHUB_ENV">> ${GITHUB_ENV}>>$GITHUB_ENV
Untrusted input sources including:
github.event.pull_request.titlegithub.event.pull_request.bodygithub.event.pull_request.head.refgithub.event.pull_request.head.labelgithub.event.pull_request.head.repo.full_name- And other user-controlled fields
Normal workflow triggers where permissions are limited
Why This Pattern Should Be Fixed #
Even in normal workflows, writing untrusted input to $GITHUB_ENV is problematic:
- Unpredictable Behavior: Environment pollution can cause hard-to-debug issues
- CI/CD Reliability: Test and build results may become unreliable
- Future-Proofing: If workflow gains privileges later, the vulnerability becomes critical
- Code Quality: Encourages secure coding practices
Difference from Critical Severity #
| Aspect | Critical (Privileged) | Medium (Normal) |
|---|---|---|
| Permissions | Write access, secrets | Read-only |
| Impact | Repository compromise | Workflow behavior manipulation |
| Secret Access | Yes | No |
| Attack Surface | High | Medium |
| Urgency | Immediate fix required | Should be fixed |
Real-World Impact #
Environment variable injection in normal workflows can lead to:
- CI/CD Confusion: Misleading build or test results
- Quality Gate Bypass: Altered environment skips critical checks
- Developer Friction: Hard-to-reproduce bugs in CI
- Escalation Path: Becomes critical if workflow permissions change
Best Practices #
- Prefer Direct Usage: Use
env:blocks instead of writing to$GITHUB_ENVwhen possible - Sanitize Inputs: Always use
tr -d '\n'when writing to$GITHUB_ENV - Use Heredoc for Multi-line: Use unique delimiters for multi-line values
- Validate Permissions: Ensure workflows have minimal necessary permissions
- Regular Audits: Review workflows for privilege escalation paths
Related Rules #
- envvar-injection-critical: Detects the same pattern in privileged workflows (higher severity)
- code-injection-medium: Detects direct code injection in normal contexts
- permissions: Ensures workflows follow least-privilege principle
Rule Interactions #
You may see both envvar-injection-medium and code-injection-medium errors on the same line. This is intentional and provides defense in depth:
- code-injection-medium: Detects untrusted input anywhere in run scripts and isolates it to environment variables
- envvar-injection-medium: Specifically detects $GITHUB_ENV writes and adds newline sanitization
Both auto-fixes work together. Apply both for complete protection:
code-injectionmoves expressions toenv:sectionenvvar-injectionaddstr -d '\n'to $GITHUB_ENV writes
For detailed explanation of how these rules interact, see envvar-injection-critical Rule Interactions.
References #
- CodeQL: Environment Variable Injection (Medium)
- GitHub Security: Script Injection
- GitHub Actions: Environment Variables
Testing #
To test this rule with example workflows:
# Detect vulnerable patterns
sisakulint script/actions/envvar-injection-medium.yaml
# Apply auto-fix
sisakulint -fix on script/actions/envvar-injection-medium.yaml
Configuration #
This rule is enabled by default. To disable it, use:
sisakulint -ignore envvar-injection-medium
When to Use Critical vs Medium #
Choose the appropriate severity based on workflow trigger:
- Use Critical Rule: For
pull_request_target,workflow_run,issue_comment,issues,discussion_comment - Use Medium Rule: For
pull_request,push,schedule,workflow_dispatch
Both rules use the same detection and fix logic, but differ in severity classification based on the attack surface and potential impact.