Why is this an issue?

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:

What is the potential impact?

If credentials persisted in the .git directory are uploaded, an attacker who gains access to the uploaded artifacts can:

Credential Exposure

The credentials are stored in plain text in the artifact, allowing unauthorized access to repository resources.

Unauthorized Access

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.

Supply Chain Compromise

An attacker with the extracted credentials can modify workflows, inject malicious code, or publish malicious packages, potentially compromising the entire supply chain.

How to fix it

There are two primary ways to fix this vulnerability:

Code examples

Noncompliant code example

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

Compliant solution

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

How does this work?

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.

Resources

Documentation

Standards