By default, actions/checkout persists credentials to .git/config. When artifacts are uploaded using
actions/upload-artifact, these persisted credentials can be exposed in artifacts.
The vulnerability occurs when:
.git/config by default if a broad path is given e.g. ., *. Note: version 3.2+ contains a backported fix that
excludes hidden files by default.include-hidden-files:
true is set and a broad path is given e.g. . or * without manually excluding the .git directory.If credentials persisted in the .git directory are uploaded, an attacker who gains access to the uploaded artifacts can:
The credentials are stored in plain text in the artifact, allowing unauthorized access to repository resources.
An attacker with the extracted credentials can perform actions on behalf of the workflow, such as reading sensitive data, modifying code, creating releases, or accessing other repositories the credentials have permissions for.
An attacker with the extracted credentials can modify workflows, inject malicious code, or publish malicious packages, potentially compromising the entire supply chain.
There are two primary ways to fix this vulnerability:
actions/checkout from ever writing
the credentials to the .git/config file. Set persist-credentials: false in actions/checkout step.persist-credentials: true and include-hidden-files: true,
add !.git/ to the path input of the actions/upload-artifact step to explicitly exclude the sensitive .git
directory.
jobs:
test-job:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: true
- name: Upload artifact
uses: actions/upload-artifact@v4.1.1 # Noncompliant
with:
name: repo-artifact
path: .
jobs:
test-job:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: true
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: repo-artifact
path: |
. # Noncompliant
include-hidden-files: true
If actions/upload-artifact version is vulnerable (< 3.2 or >= 4.0 and < 4.4), upgrading to version 3.2+ or 4.4+ will fix this
by automatically ignoring hidden files from being uploaded.
jobs:
test-job:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: true
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: repo-artifact
path: .
If persist-credentials: true & include-hidden-files: true are used together, !.git must be explicitly
included to prevent the .git directory from being uploaded:
jobs:
test-job:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: true
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: repo-artifact
path: |
.
!.git
include-hidden-files: true
By default, actions/checkout persists the credentials to .git/config to enable Git operations.
When artifacts are uploaded that include the .git directory (either explicitly or through patterns like . or
**/*), the persisted credentials are included in the artifact. An attacker who gains access to the artifact can extract the credentials
from .git/config.
For upload-artifact version 3.2+ or 4.4+, when using include-hidden-files: true, explicitly excluding !.git/
from the artifact path provides defense-in-depth protection.