OWASP OSS Risk 2: Compromise of Legitimate Package
OWASP OSS Risk 2: Explore the compromise of legitimate open-source packages, with an in-depth case study of the tj-actions/changed-files GitHub Action supply chain attack.
OWASP OSS Risk 2: Explore the compromise of legitimate open-source packages, with an in-depth case study of the tj-actions/changed-files GitHub Action supply chain attack.
OWASP OSS Risk 2: Explore the compromise of legitimate open-source packages, with an in-depth case study of the tj-actions/changed-files GitHub Action supply chain attack.
OWASP OSS Risk 2: Explore the compromise of legitimate open-source packages, with an in-depth case study of the tj-actions/changed-files GitHub Action supply chain attack.
OWASP OSS Risk 2: Explore the compromise of legitimate open-source packages, with an in-depth case study of the tj-actions/changed-files GitHub Action supply chain attack.

This article is part of a 10-part series on the Top 10 OSS Risks:
- OSS-RISK-1 Known Vulnerabilities
- OSS-RISK-2 Compromise of Legitimate Package (this article)
- OSS-RISK-3 Name Confusion Attacks (coming soon)
- OSS-RISK-4 Unmaintained Software (coming soon)
- OSS-RISK-5 Outdated Software (coming soon)
- OSS-RISK-6 Untracked Dependencies (coming soon)
- OSS-RISK-7 License Risk (coming soon)
- OSS-RISK-8 Immature Software (coming soon)
- OSS-RISK-9 Unapproved Change (Mutable) (coming soon)
OSS-RISK-10 Under/Over-Sized Dependency (coming soon)
The Top 10 Risks for Open Source, developed by the Station 9 research team at Endor Labs, is an OWASP incubator project. A set of critical risks to applications leveraging open source software (OSS) dependencies, the list includes two categories of risks:
- Security risks can result in the compromise of system or data confidentiality, integrity, or availability.
- Operational risks can endanger software reliability or increase the efforts and investments required to develop, maintain, or operate a software solution.
In this 10-part series we explore each risk in depth, including the relevance of each risk and how you can factor them into your security programs. Below we take a closer look at the second risk: Compromise of Legitimate Package.
Risk Category: Security
What is a Legitimate Package?
Given that open-source software (OSS) is estimated to be present in 70-90% of applications, it plays a crucial role in modern development. This vast ecosystem, valued at an estimated $8.8 trillion [1], offers developers free access to powerful tools and libraries, accelerating innovation and reducing costs. By leveraging OSS, teams can build more efficiently, avoid reinventing the wheel, and benefit from collective expertise. However, integrating open-source software also comes with risks—especially the potential compromise of legitimate packages, a growing concern in today's software supply chain.
A legitimate package is a reusable software component that is widely recognized as trustworthy, maintained by reputable developers or organizations, and distributed through official channels like npm, PyPI, or Maven Central. These packages are usually open-source, and supported by active maintenance, documentation, and regular version updates. With proper licensing and widespread adoption by trusted projects, legitimate packages are essential building blocks for modern software development, saving software companies a lot of time and money.
Developers integrate these legitimate packages as dependencies using package managers, often pinning (locking) versions or setting version ranges to ensure stability. Package upgrades are routine, driven by new features, performance enhancements, or critical security patches.
What is a Compromise of a Legitimate Package? Trusting the Source, but not the Delivery
%20(1).png)
As opposed to the first OWASP OSS Risk, Known Vulnerabilities, which is about publicly disclosed security bugs in the source code, an increasingly common attack vector is to compromise a legitimate package somewhere between you and the trusted maintainer. It’s like if you order takeout from your favorite restaurant: you trust the chef, but what about the DoorDasher?
In this type of attack, attackers compromise resources that are part of an existing legitimate project or of the distribution infrastructure in order to inject malicious code into a component, e.g., through hijacking the accounts of legitimate project maintainers, exploiting vulnerabilities in package repositories, or becoming maintainers themselves.
Compromised packages can then execute malicious code on developer or end-user systems, jeopardizing the confidentiality, integrity, and availability of systems and the data they process. They also enable attackers to move laterally across connected systems and services, amplifying the potential damage to an organization's infrastructure.
How are Legitimate Packages Compromised?
Bad actors can compromise legitimate packages from the point of development all the way to downloading. Below, we take a closer look at three critical attack vectors that highlight the complexity and potential consequences of such compromises (bear with me, there are a lot of them!), followed by a case study of last week’s GitHub Action tj-actions/changed-files supply chain attack.
- Development Stage: Inject malicious code into legitimate package source code
- Build Stage: Inject malicious code during the build of legitimate package
- Publish/Download Stage: Distribute malicious version of legitimate package

1. Development Stage: Inject Malicious Code into Legitimate Package Source Code
Malicious code is injected into the source code of a trusted project so that downstream users unknowingly incorporate harmful elements. Attackers employ three specific techniques: Hypocrite merge request, contribute as maintainer, and tampering with the version control system.
Hypocrite Merge Request
Attackers sneak in malicious code by submitting seemingly beneficial contributions to a project, such as new features, tests, or documentation. The contributions often target areas subjected to less rigorous scrutiny and sometimes the malicious code is obfuscated by splitting it up into multiple commits or by exploiting rendering weaknesses in the user interface of the tools used for manual code reviews. Once accepted, the malicious code—whether a backdoor or an intentional vulnerability—propagates to all users of the package. Examples:
- PR Sneaking
- CVE-2021-42574: Bidirectional override characters used to cause visual code obfuscation
- CVE-2021-42694: Homoglyph attacks
Contribute as Maintainer
Attackers gain maintainer-level access to a project, enabling them to push malicious changes directly. This access can be obtained through various methods:
- Bribe or Blackmail Legitimate User: Coerce an existing maintainer into granting access or making changes. Example: ATT&CK T1199: Trusted Relationship
- Take-over Legitimate Account: Compromise the account of a maintainer via bruteforce, phishing, credential theft, exposed secrets, session hijacking, or resurrecting an expired email domain and changing the password for the account. People sometimes use the same password for multiple accounts, so even seemingly unrelated data breaches can be leveraged to gain access to a given account. Examples:
- Become Maintainer: Establish trust within the community to secure a maintainer role, then introduce malicious elements. Example: In the 2024 case of XZ Utils, the attacker socially engineered their way into becoming a maintainer over a period of about three years, which allowed them to insert the backdoor into the code. Learn more in XZ is A Wake Up Call For Software Security: Here's Why and XZ Backdoor: How to Prepare for the Next One.
- Change Ethos: An existing maintainer alters their intentions, perhaps due to ideological shifts or monetary gain. Example: Open source developer corrupts widely-used libraries, affecting tons of projects
- Compromise Maintainer System: Exploit vulnerabilities, weak configuration, or malicious components in the maintainer’s systems to introduce unauthorized changes. Example: ATT&CK T1190: Exploit Public-Facing Application
Tamper with Version Control System
Attackers exploit vulnerabilities or misconfigurations in version control systems, or gain access via a compromised administrator account, to insert malicious code. While many projects use version control services like GitHub, some still manage their own systems, making them potential targets. Example: CVE-2018-17456: Remote code execution via a malicious .gitmodules file
2. Build Stage: Inject Malicious Code During the Build of Legitimate Package
Rather than targeting source code, attackers may compromise the build process, resulting in infected binaries that are distributed to end-users. Techniques include: Run malicious builds, tampering with build jobs as a maintainer, and tampering with an exposed build system.
Run Malicious Build
In environments where build systems share resources (e.g., plugins or caches), attackers can introduce malicious builds to contaminate shared resources. Subsequent builds by legitimate projects unknowingly execute or incorporate the malicious elements. Example: The Octopus Scanner Malware: Attacking the open source supply chain
Tamper with Build Job as Maintainer
Attackers impersonate maintainers or exploit weak access controls to modify build job definitions (see “Contribute as Maintainer” above). By injecting malicious configurations or code, they ensure compromised binaries are produced and distributed.
Tamper with Exposed Build System
Build systems accessible online can be exploited via vulnerabilities, weak configurations, or compromised administrator accounts. Attackers may manipulate build processes or artifacts, resulting in malicious binaries distributed through trusted channels. Example: ATT&CK T1190: Exploit Public-Facing Application
3. Publish/Download Stage: Distribute Malicious Version of Legitimate Package
By replacing legitimate packages with malicious versions, attackers trick developers into downloading and using infected code. Common techniques include: Distributing as a package maintainer, injecting into the hosting system, dangling references, masking legitimate packages, and preventing updates to non-vulnerable versions.
Distribute as Package Maintainer
Attackers gain access to a package maintainer account (see “Contribute as Maintainer” above) and with access to the deployment workflows of a project, they upload new malicious versions of existing packages to official distribution channels. Example: Malicious code in the PureScript npm installer
Inject into the Hosting System
Attackers gain access to the hosting system via vulnerabilities, weak configurations, or compromised administrator accounts and bypass standard deployment processes to tamper with existing binaries on distribution platforms (e.g., npm, PyPI, or CDNs). By altering files directly in hosting systems, they can compromise all downloads of any package hosted on that registry. Example: Beware of hacked ISOs if you downloaded Linux Mint on February 20th!
Dangling Reference
When a package is deprecated, removed, or renamed, attackers can reintroduce it under the same name but with malicious content. Users with lingering references to the old package inadvertently adopt the compromised version. Example: Repo Jacking: Exploiting the Dependency Supply Chain
Mask Legitimate Package
Attackers manipulate the resolution process for package URLs through techniques like DNS cache poisoning, Man-in-the-Middle attacks, or tampering with dependency resolution mechanisms. Users attempting to download legitimate packages are redirected to malicious versions. The infamous dependency confusion attack falls into this category. Example: Dependency Confusion: How I Hacked Into Apple, Microsoft and Dozens of Other Companies
Prevent Update to Non-Vulnerable Version
Attackers forge metadata or replay signed metadata to block updates, keeping users reliant on vulnerable versions. Techniques include introducing unsatisfiable dependencies or manipulating package metadata.
Case Study: The GitHub Action tj-actions/changed-files Supply Chain Attack
Overview
GitHub Actions are used in CI/CD workflows to automate tasks such as testing, building, and deployment. As such, they often have access to sensitive information such as repository secrets, API keys, and deployment credentials, making them a valuable target for supply chain attacks.
On March 14, 2025, the popular open-source GitHub action tj-actions/changed-files was compromised via several of the attack vectors described above, potentially impacting over 23,000 repositories [2][3]. The incident has been assigned CVE-2025-30066 (tj-actions) and CVE-2025-30154 (reviewdog).
Attackers used a compromised personal access token (PAT) to push a malicious commit disguised as coming from the automation tool renovatebot to the tj-actions/changed-files GitHub repository, and then changed all tags to point to that commit. This code change caused secrets and configuration values to be printed to the GitHub action logs for all projects using the action not pinned to a specific commit SHA.


Learn more in GitHub Action tj-actions/changed-files supply chain attack: what you need to know.
Attack Vectors
The investigation is still ongoing but, as far as we can tell [4] [5] [6] [7] [8] [9] [10], here is the likely step-by-step sequence of actions, and corresponding attack vectors, performed by the attackers:
Summary
The tj-actions/changed-files supply chain attack highlights the risks of compromised credentials and dependency hijacking in CI/CD workflows. By leveraging a chain of exploits—including a malicious commit, a hijacked contributor account, and a manipulated Git tag—attackers could have exfiltrated thousands of credentials if the attack wasn’t discovered so quickly. This incident underscores the importance of pinning dependencies to specific commit SHAs, monitoring for suspicious activity, and securing contributor accounts to mitigate similar threats in the future.
How to Dodge the Bullet: Protecting Against Compromise of Legitimate Packages
Using open-source software comes with inherent risks, including the potential compromise of legitimate packages. To mitigate this threat, implement the following proactive security controls.
For more detailed safeguards for each attack vector discussed here, visit here.
General Security Controls Against Package Subversion
- Audit and Remove Unused Dependencies:
- Regularly audit projects to identify and remove unnecessary dependencies, reducing the likelihood of using compromised packages.
- Version Pinning and Lockfiles:
- Use lockfiles (package-lock.json, yarn.lock, poetry.lock) to maintain precise package versions.
- Leverage integrity checks within lockfiles to quickly detect if a package has been maliciously modified.
- Build Dependencies from Source:
- Build critical dependencies from their source or maintain internal forks to verify and control all code changes explicitly.
- Establish an Internal Package Mirror:
- Use internal package registries to mirror, vet, and control the exact versions of packages your organization trusts.
- Integrate regular malware and vulnerability scans into your development pipeline:
- There is an obvious trade off between using version pinning and automatically updating to the latest version [11]. In the first case, you reduce the risk of compromised legitimate packages. In the second, you stay up to date with the latest security updates. Regardless of which approach you choose there are benefits of running regular malware and vulnerability scans on your entire development pipeline.
GitHub Action Workflow Specific Controls Against Package Subversion
- Pin Actions to Specific SHAs:
- Always pin GitHub Actions to specific commit SHAs to avoid using compromised action updates.
- Fork and Maintain Critical Actions Internally:
- Internally fork and maintain important actions to strictly control the changes introduced to your workflows.
- Secure Access Tokens and Credentials:
- Regularly rotate Personal Access Tokens (PATs) and limit their scope strictly to required permissions.
- Regularly audit and tightly manage repository secrets.
- Use verified GitHub Actions
- Verified GitHub actions help you identify the creators and the community supporting them.
Detecting compromised packages with Endor Labs
As part of our Software Composition Analysis (SCA) tool, Endor Labs helps you monitor for known malicious packages and detect suspicious code snippets and behaviors. Read Detect Malicious Packages Among Your Open Source Dependencies to learn more about how this works and book a demo to talk through your use cases
References
- https://www.library.hbs.edu/working-knowledge/open-source-software-the-nine-trillion-resource-companies-take-for-granted (Harvard Business School)
- https://github.com/tj-actions/changed-files/network/dependents (GitHub)
- https://www.endorlabs.com/learn/blast-radius-of-the-tj-actions-changed-files-supply-chain-attack (Endor Labs)
- https://www.endorlabs.com/learn/github-action-tj-actions-changed-files-supply-chain-attack-what-you-need-to-know (Endor Labs)
- https://github.com/tj-actions/changed-files/issues/2464 (GitHub)
- https://github.com/reviewdog/reviewdog/issues/2079 (GitHub)
- https://pulse.latio.tech?utm_source=navbar&utm_medium=web (Latio)
- https://www.wiz.io/blog/github-action-tj-actions-changed-files-supply-chain-attack-cve-2025-30066 (Wiz)
- https://www.wiz.io/blog/new-github-action-supply-chain-attack-reviewdog-action-setup (Wiz)
- https://unit42.paloaltonetworks.com/github-actions-supply-chain-attack (Palo Alto Networks)
- https://arxiv.org/pdf/2502.06662 (Carnegie Mellon University)