PATH Injection Rule (Critical) Overview #
This rule detects PATH injection vulnerabilities when untrusted input is written to $GITHUB_PATH within privileged workflow contexts. Privileged workflows have write permissions or access to secrets, making PATH injection particularly dangerous as attackers can hijack command execution by prepending malicious directories.
Key Features: #
- Privileged Context Detection: Identifies dangerous patterns in
pull_request_target,workflow_run,issue_comment, and other privileged triggers - GITHUB_PATH Write Detection: Analyzes scripts that write to
$GITHUB_PATHfile - Auto-fix Support: Automatically validates paths using
realpathbefore writing to $GITHUB_PATH - Zero False Positives: Does not flag already-safe patterns with proper path validation
Security Impact #
Severity: Critical (9/10)
PATH injection in privileged workflows represents a critical vulnerability in GitHub Actions:
- Command Hijacking: Attackers can prepend malicious directories to PATH, causing legitimate commands to execute attacker-controlled binaries
- Build Process Compromise: The
npm,pip,go, or other build tools can be replaced with malicious versions - Secret Exfiltration: Replaced commands can capture secrets and credentials passed as arguments
- Supply Chain Attacks: Compromised build tools can inject backdoors into artifacts
- Persistence Across Steps: PATH modifications persist throughout the job, affecting all subsequent commands
This vulnerability is classified as CWE-426: Untrusted Search Path and CWE-427: Uncontrolled Search Path Element, and aligns with OWASP CI/CD Security Risk CICD-SEC-04: Poisoned Pipeline Execution (PPE).
Privileged Workflow Triggers #
The following triggers are considered privileged because they run with write access or secrets:
pull_request_target: Runs with write permissions and secrets, but triggered by untrusted PRsworkflow_run: Executes with elevated privileges after another workflow completesissue_comment: Triggered by comments from any user, including external contributorsissues: Triggered by issue events, potentially from untrusted sourcesdiscussion_comment: Triggered by discussion comments from any user
Example Vulnerable Workflow #
Consider this dangerous workflow that writes PR data to $GITHUB_PATH in a privileged context:
name: Build PR Tools
on:
pull_request_target: # PRIVILEGED: Has write access and secrets
types: [opened, synchronize]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
# CRITICAL VULNERABILITY: Untrusted path written to GITHUB_PATH
- name: Add PR tools to PATH
run: |
echo "${{ github.event.pull_request.head.ref }}/tools" >> "$GITHUB_PATH"
- name: Build
run: |
npm install # Could execute malicious 'npm' from attacker's path!
npm run build
Attack Scenario #
How PATH Injection Exploits Privileged Workflows:
Attacker Creates Malicious PR: Opens a PR with a branch name crafted to inject a path:
Branch: ../../tmp/evilOr uses a crafted directory structure containing malicious binaries.
Workflow Triggers:
pull_request_targetruns with write permissions and secretsPATH Hijacked: The malicious path is prepended to $GITHUB_PATH:
# Attacker's path gets added echo "../../tmp/evil/tools" >> "$GITHUB_PATH" # Now PATH becomes: /tmp/evil/tools:/usr/local/bin:/usr/bin:...Commands Hijacked: Subsequent steps execute attacker-controlled binaries:
- name: Build and deploy run: | npm install # Executes /tmp/evil/tools/npm instead of real npm python setup.py build # Executes attacker's pythonCode Execution Achieved: The attacker’s fake
npmorpython:- Captures all arguments (including secrets)
- Exfiltrates credentials via network calls
- Injects backdoors into build artifacts
- Modifies source code before compilation
What Makes This Critical #
Privileged workflows with PATH injection are particularly dangerous because:
- Write Access: Workflows can modify repository content, create releases, and manage secrets
- Command Interception: Unlike code injection, PATH hijacking intercepts ALL commands
- Stealth: Fake commands can call real commands after exfiltration, hiding the attack
- Supply Chain Impact: Compromised builds can poison production deployments
Safe Pattern (Using Path Validation with realpath) #
The recommended approach is to validate paths using realpath:
name: Build PR Tools (Safe)
on:
pull_request_target:
jobs:
build:
runs-on: ubuntu-latest
steps:
# SAFE: Validate path before adding to GITHUB_PATH
- name: Add tools to PATH safely
env:
PR_REF_PATH: ${{ github.event.pull_request.head.ref }}
run: |
# realpath resolves the path and ensures it's absolute and canonical
# This prevents path traversal attacks
echo "$(realpath "$PR_REF_PATH")/tools" >> "$GITHUB_PATH"
- name: Build
run: |
npm install # Safe - PATH contains validated paths only
npm run build
Auto-Fix Example #
sisakulint can automatically fix this vulnerability:
Before (Vulnerable):
- name: Add tools to PATH
run: |
echo "${{ github.event.pull_request.head.ref }}/bin" >> "$GITHUB_PATH"
After Auto-Fix (Safe):
- name: Add tools to PATH
env:
PR_HEAD_REF_PATH: ${{ github.event.pull_request.head.ref }}
run: |
echo "$(realpath "$PR_HEAD_REF_PATH")/bin" >> "$GITHUB_PATH"
Detection Details #
The rule detects:
Direct writes to $GITHUB_PATH using various formats:
>> $GITHUB_PATH>> "$GITHUB_PATH">> '${GITHUB_PATH}'>>$GITHUB_PATH
Untrusted input sources including:
github.event.pull_request.head.refgithub.event.pull_request.head.shagithub.event.issue.titlegithub.event.comment.body- And other user-controlled fields
Privileged workflow triggers where the impact is critical
Why This Pattern is Dangerous #
Writing untrusted input to $GITHUB_PATH without validation allows attackers to:
- Path Traversal: Use
../sequences to reference directories outside the workspace - Command Hijacking: Place malicious executables that shadow legitimate commands
- Build Tool Replacement: Replace
npm,pip,go,cargo, etc. with trojaned versions - Persistent Compromise: The modified PATH affects ALL subsequent steps
Real-World Impact #
PATH injection in privileged workflows can lead to:
- Supply Chain Compromise: Trojaned build tools inject backdoors into releases
- Secret Theft: Fake commands capture GITHUB_TOKEN and other secrets
- Repository Takeover: With write permissions, attackers can push malicious code
- Artifact Poisoning: Modified builds contain hidden malware
Related Rules #
- envpath-injection-medium: Detects the same pattern in normal (non-privileged) workflows
- envvar-injection-critical: Detects environment variable injection via $GITHUB_ENV
- code-injection-critical: Detects direct code injection in privileged contexts
- untrustedcheckout: Detects unsafe checkout of PR code
References #
- CodeQL: PATH Injection (Critical)
- GitHub Security: Script Injection
- OWASP: Uncontrolled Search Path Element
- OWASP Top 10 CI/CD Security Risks
Testing #
To test this rule with example workflows:
# Detect vulnerable patterns
sisakulint script/actions/envpath-injection-critical.yaml
# Apply auto-fix
sisakulint -fix on script/actions/envpath-injection-critical.yaml
Configuration #
This rule is enabled by default. To disable it, use:
sisakulint -ignore envpath-injection-critical