Research report · Cloud, application and infrastructure security
Poisoned dependencies: what 232,930 malicious-package reports say about open-source supply chain risk
An analysis of every malicious-package record in the OSV database from January 2023 to November 2026, with a registry check of how long harmful npm packages stayed available.
1Executive summary
Modern software is assembled from open-source packages downloaded from public registries such as npm and PyPI. Attackers publish malicious packages there, and occasionally take over trusted ones. Each discovery is recorded in public databases, and the largest of these, OSV, now holds hundreds of thousands of malicious-package records.
We analysed all 232,930 malicious-package records published in OSV between January 2023 and 12 November 2026 across eight ecosystems, classified each by what it reportedly does, tested which PyPI names imitate popular projects, and checked a random sample of npm records against the registry to measure how long harmful packages stayed available. Most records turn out to be spam; the real threat is smaller, mostly theft, and stays available for weeks.
Key findings
Most malicious-package records are spam, not attacks. 60.6% of the 232,930 records are token-farming spam, and 99.7% of those were filed in a single month, November 2025. Raw counts of "malicious packages" therefore say little about risk.
Where the behaviour of harmful packages is described, 81.5% steal something: credentials, tokens, browser data or cryptocurrency. But 59.1% of harmful records give no detail at all.
Trusted packages are compromised in waves. 2,155 records concern legitimate packages taken over, concentrated in five bursts between September 2025 and August 2026, several of them self-spreading worms.
Harmful npm packages stayed available for a median of 35 days before npm removed them, and only 15.5% were removed within a day. In 71% of cases npm acted before the OSV record appeared, so feeds built on OSV mostly arrive after the fact.
Typosquatting is a minority tactic. Only 9.6% of malicious PyPI names imitate one of the 15,000 most-downloaded projects; checks for look-alike names alone would miss nine in ten.
What this means
- Boards and executives
- Open-source components are part of the supply chain and need the same oversight as other suppliers. Ask whether the organisation knows which packages it uses, where they come from, and how quickly it can find and contain a bad one.
- Security leaders
- Plan on the basis that a malicious package will be installed before any public feed flags it. Prioritise controls that limit what an install can reach, and a tested process to find past installs and rotate the credentials they could have taken.
- Engineering teams
- Pull packages through a controlled registry, pin versions with lockfiles, turn off install scripts by default, keep secrets out of build environments, and protect your own publishing accounts with trusted publishing and strong multi-factor authentication.
2Scope and questions
Research questions
- How many malicious packages are reported in the main open-source registries, and how much of that is a genuine threat?
- What do harmful packages do, and how do attackers get them installed?
- How long do harmful packages stay available, and how early do public feeds warn defenders?
In scope
- All 232,930 malicious-package (MAL-) records in OSV published from 1 January 2023 to 12 November 2026, after excluding 363 withdrawn records and two marked as false positives
- Eight ecosystems: npm, PyPI, RubyGems, NuGet, crates.io, Go, Maven and Packagist
- A fixed random sample of 600 npm records from 2025 and 2026 (300 harmful, 300 spam), checked against the npm registry on 12 November 2026
Out of scope
- How many times each package was downloaded or installed, which OSV does not record
- Vulnerabilities in legitimate packages (non-malicious flaws), which are covered in reports EFF-RR-2026-001 and EFF-RR-2026-002
- Removal times outside npm: PyPI and the other registries delete malicious packages without leaving a record of when
3Methodology
We downloaded the OSV dumps for eight ecosystems on 12 November 2026 and kept every record whose identifier begins with MAL-, the prefix OSV uses for malicious packages imported from the OpenSSF malicious-packages project. Records that were withdrawn or marked as false positives were excluded.
Each record was classified by written rules applied to its summary and description, in a fixed order with the first match winning: spam and token farming; compromised legitimate packages; dependency confusion and reconnaissance; cryptocurrency theft; credential and data theft; malware delivery and remote access; contact with a known malicious domain; and, where none applied, malicious with no detail given. We call every category except spam and reconnaissance "harmful". The rules were refined by reading samples of matched text; for example, an early rule for compromised packages also caught a package named hijack_publish and was removed.
For PyPI, we compared each harmful name with the 15,000 most-downloaded projects (ranking dated 1 November 2026), counting a name as imitating one if it matched exactly; was a close misspelling of a top-5,000 project of five or more characters (the two names become identical after deleting at most one character from each, or after swapping two neighbouring letters); or combined a top-1,000 project name with other words. For npm, we checked 300 harmful and 300 spam records from 2025 and 2026, drawn with a fixed random seed, against the registry. When npm removes a malicious package it replaces it with a placeholder version, 0.0.1-security, and keeps the publication times of the original versions. We treat the placeholder time as the removal time and measure from the first published version.
Sources
| Source | How it was used | Reliability |
|---|---|---|
| OSV database dumps, eight ecosystems, retrieved 12 November 2026 | Every malicious-package record: package, ecosystem, publication date, description and reporting source. | Authoritative aggregator. Content depends on what reporters submit, and many descriptions are generic. |
| OpenSSF malicious-packages project | The upstream source of the MAL- records, and the reporters credited for each. | Primary open data. One automated reporter accounts for most records. |
| npm registry metadata, 600 sampled packages, 12 November 2026 | Version publication times and the time of npm’s security placeholder for each sampled package. | Primary source for timing; the placeholder time is taken as the removal time. |
| Top PyPI Packages (30-day download ranking, 1 November 2026) | The 15,000 most-downloaded PyPI projects, used to test name imitation. | Widely used community dataset derived from PyPI download statistics. Reflects current, not historical, popularity. |
Review
- Author review: Effycace Research Team, authoring team
Data availability
4Findings
Finding 1
Most malicious-package records are spam, and npm dominates
High confidence
Of the 232,930 records, 141,131 (60.6%) describe spam: packages mass-published to farm rewards from the tea.xyz token scheme rather than to attack the people who install them. Almost all of it is on npm, and 140,728 of those records (99.7%) were filed in November 2025, when the campaign was flagged in bulk. A chart of "malicious packages per year" is mostly a chart of that one event.
The remaining 89,865 records (38.6%) describe harmful packages; a further 1,934 describe dependency-confusion probes and other reconnaissance, which we report separately. Harmful records rose from 8,757 in 2023 to 51,710 in 2025, and reached 17,468 in 2026 by 12 November.
npm accounts for 92.7% of all records and 82.3% of harmful ones. PyPI follows with 10,747 harmful records, then RubyGems (4,307) and NuGet (782). RubyGems shows the sharpest recent change: 3,372 harmful records in 2026, against 128 in 2025. The other four ecosystems together have 45.
| Ecosystem | All records | Spam | Harmful | Harmful in 2026 |
|---|---|---|---|---|
| npm | 215,814 | 140,913 | 73,984 | 12,859 |
| PyPI | 11,973 | 217 | 10,747 | 1,182 |
| RubyGems | 4,316 | 1 | 4,307 | 3,372 |
| NuGet | 782 | 0 | 782 | 22 |
| crates.io, Go, Maven, Packagist | 45 | 0 | 45 | 33 |
| All ecosystems | 232,930 | 141,131 | 89,865 | 17,468 |
Base: OSV MAL- records published 1 January 2023 to 12 November 2026, excluding 363 withdrawn and 2 false-positive records. Spam and harmful do not sum to all records because reconnaissance (1,934) is shown separately. Source: OSV dumps retrieved 12 November 2026.
Finding 2
Harmful packages mostly steal, but most records do not say what they do
Moderate confidence
Of the 89,865 harmful records, 53,071 (59.1%) say only that a package is malicious, often with a stock sentence that any computer running it should be considered compromised. That gap limits what defenders can learn from the data: a blocklist entry with no behaviour cannot tell a team which secrets to rotate.
Among the 36,794 records that do describe behaviour, theft dominates. Credential and data theft, such as stealing tokens, environment variables, browser data and SSH keys, accounts for 74.3%, and cryptocurrency theft for a further 7.2%: 81.5% in all. Contact with known malicious domains (9.0%), compromised legitimate packages (5.9%) and malware delivery or remote access (3.6%) make up the rest.
The emphasis on theft matters for response. Code of this kind typically runs when a package is installed or first imported on a developer laptop or build server, which is where tokens and cloud credentials live. Removing the package afterwards does not undo what it has already sent away.
Base: 36,794 harmful records whose description states a behaviour; 53,071 further harmful records give no detail. Category assigned by Effycace rules applied to each record’s text, published with the dataset. Source: OSV dumps retrieved 12 November 2026.
Finding 3
Trusted packages are compromised in waves
High confidence
2,155 records concern legitimate packages that attackers took over, typically by phishing a maintainer or stealing a publishing token, and then used to push a malicious version to everyone who depended on them. They are few compared with the total, but each can reach far more systems than a new package with an invented name.
They arrive in bursts. The records cluster in September 2025 (230), when widely used packages including ansi-regex, ansi-styles and DuckDB’s were compromised, the DuckDB case through a phishing attack on a maintainer, according to the records; November 2025 (793), described in the records as the "Sha1-Hulud: The Second Coming" worm; March 2026 (69, "CanisterWorm"); May 2026 (533, mostly "Mini Shai-Hulud"); and August 2026 (454, "Shai-Hulud: here we go again"). Several of these campaigns spread by themselves, using tokens stolen from one maintainer to publish to that maintainer’s other packages.
Defences based on suspicious names cannot catch these, because the name is the trusted one. What helps is limiting what any install can do, pinning versions so that a new release is not pulled in automatically, and protecting publishing accounts so that the next maintainer does not become the next source.
Base: 2,155 records classed as compromised legitimate packages, of which 2,079 fall in these five months. Campaign names are as given in the records. Source: OSV dumps retrieved 12 November 2026.
Finding 4
Harmful packages stay available for weeks, and feeds learn late
Moderate confidence
Of 300 harmful npm records from 2025 and 2026, drawn at random, npm had replaced 253 (84.3%) with its security placeholder, 28 (9.3%) had been unpublished, 12 (4.0%) were not found and 7 (2.3%) were still available. For the 238 removed packages with recorded timestamps, the median time from first publication to removal was 35 days. Only 15.5% were removed within 24 hours, and 52.1% stayed available for more than 30 days. Most (79.4%) had a single version, so the clock starts with the malicious release itself.
Public feeds lag further. In 71.0% of these cases npm removed the package before the OSV record was published. A blocklist built on OSV therefore mostly confirms what the registry has already done; its main value is in finding past installs, not preventing new ones.
This also tests a common control: refusing packages younger than a minimum age. A seven-day minimum would only have stopped the 22.7% of harmful packages that npm removed within a week. It is worth having, but not on its own. Spam behaves differently again: 45.3% of the sampled spam packages were still available, and those that npm had removed had stayed up for a median of 547 days.
Base: 238 harmful npm packages from a random sample of 300 records published in 2025 and 2026, removed with a security placeholder and with version timestamps. Measured from first version publication to placeholder publication. Source: npm registry, queried 12 November 2026; OSV dumps.
Finding 5
Look-alike names are a minority tactic
Moderate confidence
Typosquatting, publishing a package whose name is a slip of the keyboard away from a popular one, is the best-known way to get malware installed. In PyPI it is real but small. Of 11,756 harmful and reconnaissance records, 964 (8.2%) are close misspellings of a top-5,000 project, 159 (1.4%) combine a popular name with other words, and 8 (0.1%) use the exact name of a top-15,000 project, which usually means that project was itself compromised. In total, 9.6% imitate a popular project.
The most imitated names are the most widely used libraries: requests (109 imitations), beautifulsoup4 (53), colorama (44), requests-toolbelt (43) and websocket-client (40). The other 90.4% use names that do not resemble a popular project. How those packages reach their victims is mostly not recorded in the data.
Name-similarity checks are cheap and worth running, but a control that only flags look-alikes would miss nine in ten malicious packages. Knowing why each new dependency is needed, and who added it, catches more.
| Popular project | Malicious imitations | Example |
|---|---|---|
| requests | 109 | erquests, requests-flask, google-requests |
| beautifulsoup4 | 53 | bautifulsoup4, beatuifulsoup |
| colorama | 44 | clorama, coloarma |
| requests-toolbelt | 43 | reqeusts-toolbelt |
| websocket-client | 40 | webocket-client |
Base: 1,131 of 11,756 harmful and reconnaissance PyPI records whose names imitate a project in the top 15,000 by 30-day downloads (ranking of 1 November 2026). Popularity is current, not as at the time of each attack. Source: OSV dumps; Top PyPI Packages.
5Recommendations
Recommendations are ordered by priority. Effort is a broad estimate for a mid-sized organisation; your own will depend on what is already in place.
| # | Recommendation | Owner | Priority | Effort | Framework reference |
|---|---|---|---|---|---|
| 1 | Install packages only through a controlled internal registry or proxy that can block known-malicious versions and hold new packages for review. | Engineering platform team | High | Medium | NIST SSDF PW.4 CIS Controls v8.1 16.4 |
| 2 | Pin dependencies with lockfiles and turn off install scripts by default, allowing them only for packages that need them. | Engineering leads | High | Low | NIST SSDF PS.1 npm ignore-scripts |
| 3 | Keep long-lived secrets out of developer and build environments; use short-lived, narrowly scoped credentials so that a stolen token is of little use. | Security architecture | High | Medium | NIST CSF 2.0 PR.AA-05 |
| 4 | Protect your own published packages with trusted publishing and phishing-resistant multi-factor authentication on maintainer accounts. | Package maintainers | High | Low | PyPI and npm trusted publishing NIST SSDF PS.1 |
| 5 | Keep a software inventory (SBOM) for each application and check it daily against the OSV malicious-package feed; when a match is found, treat it as an incident and rotate every credential the affected machine could reach. | Security operations | Medium | Medium | NIST CSF 2.0 ID.AM-02, RS.MI-02 |
| 6 | Add a minimum package age and look-alike name checks to dependency review, as supplements rather than the main defence. | Engineering leads | Medium | Low | CIS Controls v8.1 16.4 |
6Limitations
- OSV records reflect what reporters submit. One automated reporter, Amazon Inspector, is credited on 58.1% of harmful records, and only 7.1% of all records have more than one reporter, so the data shows what scanners find more than what attackers attempt.
- Categories come from rules applied to each record’s text. 59.1% of harmful records have no usable description, and the boundary between spam, reconnaissance and harm is sometimes a judgement. The rules are published so readers can test other choices.
- Records count packages, not installations. A package downloaded once and one downloaded millions of times count the same.
- Removal times come from a random sample of 300 harmful npm records and assume that npm publishes its security placeholder when it removes a package. Packages first published before 2025 but recorded later are included and lengthen the tail. Other registries leave no removal timestamp, so they are not measured.
- The PyPI popularity ranking is from November 2026 and the imitation test catches only close spellings and simple combinations; other imitation styles are counted as not imitating.
- This report was reviewed by its author and has not yet been independently peer reviewed. We welcome corrections and will record them in the version history.
7How to read this report
Each finding carries a confidence level, which describes the quality of the evidence behind it. Where we estimate likelihood, we use fixed terms so that “likely” means the same thing every time.
- High confidence
- Based on good-quality information from several independent sources, or on a complete dataset. A high-confidence judgement can still be wrong.
- Moderate confidence
- Based on credible information, but with gaps, a limited sample or more than one plausible interpretation.
- Low confidence
- Based on scarce, fragmented or single-source information. Treat it as something to watch, not as the sole basis for a major decision.
| Term | Probability |
|---|---|
| Almost no chance | 1–5% |
| Very unlikely | 5–20% |
| Unlikely | 20–45% |
| Roughly even chance | 45–55% |
| Likely | 55–80% |
| Very likely | 80–95% |
| Almost certain | 95–99% |
8References
- OSV. Open Source Vulnerabilities database. https://osv.dev/
- OSV. Data dumps and downloads. Retrieved 12 November 2026. https://google.github.io/osv.dev/data/
- Open Source Security Foundation. OpenSSF malicious-packages project. https://github.com/ossf/malicious-packages
- Open Source Security Foundation. OSV schema. https://ossf.github.io/osv-schema/
- van Kemenade, H. Top PyPI Packages: 30-day download ranking, updated 1 November 2026. https://hugovk.github.io/top-pypi-packages/
- MITRE. CWE-506: Embedded Malicious Code. https://cwe.mitre.org/data/definitions/506.html
- National Institute of Standards and Technology. (2022). Secure Software Development Framework (SSDF) Version 1.1. NIST SP 800-218. https://doi.org/10.6028/NIST.SP.800-218
- National Institute of Standards and Technology. (2024). The NIST Cybersecurity Framework (CSF) 2.0. NIST CSWP 29. https://doi.org/10.6028/NIST.CSWP.29
- Center for Internet Security. CIS Critical Security Controls, version 8.1. https://www.cisecurity.org/controls/v8-1
- Python Packaging Authority. PyPI: Trusted Publishers. https://docs.pypi.org/trusted-publishers/
- npm. Trusted publishing for npm packages. https://docs.npmjs.com/trusted-publishers
- npm. CLI configuration: ignore-scripts. https://docs.npmjs.com/cli/v11/using-npm/config
9About this report
- Author
- Effycace Research Team, Effycace Solutions
- Funding and interests
- This report was funded by Effycace Solutions. No registry, reporter or vendor named in it sponsored, reviewed or approved it. Package and campaign names are as recorded in public data and do not imply wrongdoing by the legitimate maintainers whose packages were compromised.
- Distribution
- TLP:CLEAR This report may be shared freely, with attribution.
- Corrections
- If you find an error, write to contact@effycace.com. Corrections are recorded in the version history below.
How to cite
Effycace Research Team (2026). Poisoned dependencies: what 232,930 malicious-package reports say about open-source supply chain risk (Report EFF-RR-2026-008, version 1.0). Effycace Solutions Pte Ltd. https://www.effycace.com/research/reports/malicious-packages-2023-2026/
Version history
| Version | Date | Change |
|---|---|---|
| 1.0 | 12 November 2026 | First published. |
This report is general information, not advice for your specific circumstances. See our Terms of Use.