# Malware

> Malware is software built to act against the person or system running it, by stealing data, taking control, encrypting files, or hijacking compute.

Also known as: malicious software

Source: https://socket.dev/glossary/malware

Last updated: 2026-10-29

Malware, short for malicious software, is code written to act against the person or system that runs it: stealing credentials, opening remote access, encrypting or wiping files, or hijacking compute. Classic malware has to trick someone into running it. Malware in open source packages does not, because package managers, build tools, and imports execute dependency code automatically.

Automatic execution is why the problem has moved into registries. As of October 29, 2026, the [OpenSSF malicious packages dataset](https://ossf.github.io/malicious-packages/stats/) holds 239,560 published reports, and 222,478 of them are npm packages. Each one gets a `MAL-` identifier, not a CVE, so a scanner that matches CVEs reports the package as clean. Our position is that every dependency is code you are about to execute. Judge it by what it does before it is installed, not by its name, its signature, or its advisory record.

## What is malware?

Malware is software whose intended behavior works against its user. Intent is the defining property, not capability. A cleanup script and a wiper both call `rm -rf`. An error reporter and an infostealer both send an HTTPS POST. The code that separates them is usually a few lines deciding what to delete and where to send it.

Operating systems cannot make that distinction, because their permission model is built around users, not programs. Every process you start inherits your user ID. It can read `~/.ssh`, `~/.aws/credentials`, `~/.npmrc`, and every environment variable in your shell, and it can open any outbound connection your network allows. Phones sandbox each app. A developer's terminal and a CI runner do not.

So for most of its history, malware's hard problems were never about what the code could do once running. They were getting executed at all, and then staying hidden long enough to matter. Antivirus software was built around the same two problems. It inspects executables arriving from outside, matches them against signatures of known samples, and watches for suspicious behavior on the endpoint. The industry even keeps a shared test file, the [EICAR test file](https://www.eicar.org/), so administrators can confirm a scanner is wired up without handling real malware. A test file works because detection is pattern matching: every scanner agrees to flag one known string.

Ken Thompson described the trust problem underneath all of this in his 1984 Turing Award lecture, [Reflections on Trusting Trust](https://dl.acm.org/doi/10.1145/358198.358210): "You can't trust code that you did not totally create yourself." Modern applications are mostly code their developers did not create. [Socket's 2025 mid-year threat report](https://socket.dev/blog/malicious-open-source-packages-2025-mid-year-threat-report) puts third-party packages at 70 to 90 percent of a typical codebase.

## What are the main types of malware?

The main types of malware are viruses, worms, trojans, backdoors, remote access trojans, infostealers, spyware, ransomware, wipers, cryptojackers, clippers, and rootkits. Each is named for what the code does once it runs. Every type except the virus and the rootkit now has a common package-registry form, and each example below is a case our threat research team analyzed.

- **Virus.** A virus copies itself into other programs or files so it runs whenever they do. File-infecting viruses are rare in package ecosystems. The registry version of self-copying code is the worm.
- **[Worm](https://socket.dev/glossary/worm).** A worm spreads from machine to machine without anyone launching it. In [the first Shai-Hulud wave](https://socket.dev/blog/tinycolor-supply-chain-attack-affects-40-packages) in September 2025, the payload ran TruffleHog to find tokens, then used the stolen credentials to download package tarballs, inject a `bundle.js`, and republish them. The count reached nearly 500 npm packages within days.
- **Trojan horse.** A trojan poses as something useful and runs because the victim chose to install it. Most malicious packages are trojans. [The crytic-compilers package](https://socket.dev/blog/trojan-embedded-in-crytic-compilers-python-package) impersonated Trail of Bits' `crytic-compile` on PyPI and ran a bundled `s.exe` from `setup.py` on Windows. It was downloaded 388 times before removal in June 2024.
- **[Backdoor](https://socket.dev/glossary/backdoor).** A backdoor is a hidden path for the attacker to run commands later. [The shopsprint/decimal typosquat](https://socket.dev/blog/popular-go-decimal-library-typosquat-dns-backdoor) of `github.com/shopspring/decimal` added a Go `init()` function in v1.3.3 on August 19, 2023. Every five minutes it reads a DNS TXT record and executes the value. It stayed weaponized for about 33 months before disclosure in May 2026.
- **[Remote access trojan](https://socket.dev/glossary/remote-access-trojans-rats) (RAT).** A RAT gives an operator interactive control of the machine. In [North Korea's Contagious Interview campaign](https://socket.dev/blog/north-korea-contagious-interview-campaign-338-malicious-npm-packages), fake recruiters hand job candidates a repository and ask them to run `npm install`. Loaders rebuild BeaverTail in memory, which fetches InvisibleFerret, a cross-platform Python backdoor. Socket had tied more than 338 packages and 50,000 downloads to the campaign by October 2025.
- **[Infostealer](https://socket.dev/glossary/infostealer).** An infostealer collects secrets and ships them out. In [the Trivy GitHub Action compromise](https://socket.dev/blog/trivy-under-attack-again-github-actions-compromise) on March 19, 2026, attackers force-pushed 75 of the 76 version tags of `aquasecurity/trivy-action`. The payload, which labels itself the work of [TeamPCP](https://socket.dev/blog/teampcp-targeting-security-tools-across-oss-ecosystem), collected SSH keys, cloud credentials, Kubernetes tokens, and wallets from CI runners.
- **Spyware and keyloggers.** Spyware watches the user, and a keylogger records keystrokes. [The reeact-login-page typosquat](https://socket.dev/blog/malicious-npm-package-typosquats-react-login-page-to-deploy-keylogger) registered a `keydown` listener inside a React component and sent the captured keys to a PHP endpoint once a second. [13 malicious Packagist themes](https://socket.dev/blog/packagist-themes-ios-spyware) served an iOS exploit chain to site visitors, in a campaign Socket tracked from March to August 2026, and stole Keychain data, SMS, photos, and wallet seeds. In both cases the victim is the website's user, not the developer.
- **Ransomware.** Ransomware encrypts files and demands payment for the key. The npm packages `socket.oi`, `ttp-error`, `http-wrror`, and `underscoer`, published by [the npm alias xwlazssz](https://socket.dev/blog/black-basta-dependency-confusion-ambitions-and-ransomware-in-open-source-ecosystems) between 2022 and 2025, fetched an AES key from a remote server, encrypted files under `~`, `/home`, `/tmp`, `/var`, `/srv`, and `/opt`, and dropped a ransom note. They were downloaded more than 1,700 times.
- **Wiper.** A wiper destroys data with no way back. [The setan package](https://socket.dev/blog/black-basta-dependency-confusion-ambitions-and-ransomware-in-open-source-ecosystems) generated an AES key, never stored it, and encrypted every file in the working directory. [Nine NuGet packages from the alias shanhai666](https://socket.dev/blog/9-malicious-nuget-packages-deliver-time-delayed-destructive-payloads) had 9,488 downloads when we reported them in November 2025. Most of them kill the host process on 20 percent of database queries once trigger dates in August 2027 or November 2028 pass. One, Sharp7Extend, silently fails writes to industrial PLCs.
- **Cryptojacker.** A cryptojacker spends the victim's CPU mining cryptocurrency. [The Rspack compromise](https://socket.dev/blog/rspack-supply-chain-attack) shipped `@rspack/core` and `@rspack/cli` 1.1.7 in December 2024 with a `postinstall` hook. The hook downloaded XMRig, renamed it `/tmp/vant_helper`, and capped it at 75 percent of CPU threads.
- **Clipper or wallet drainer.** A clipper swaps cryptocurrency addresses so payments go to the attacker. In [the Qix compromise](https://socket.dev/blog/npm-author-qix-compromised-in-major-supply-chain-attack) on September 8, 2025, a phished maintainer account published `chalk@5.6.1`, `debug@4.4.2`, and more than a dozen other compromised packages. The payload hooked `fetch`, `XMLHttpRequest`, and `window.ethereum` in the browser and replaced recipient addresses with lookalikes picked by Levenshtein distance.
- **Rootkit.** A rootkit hides malware by modifying the kernel or system tools. Package malware rarely needs one, because it is reinstalled by design on every build. Socket's analysis of the decimal backdoor states it plainly: "The persistence mechanism is the dependency itself."

The same taxonomy covers the related terms people search for. Keystroke logging is what the keylogger above does. Memory scraping reads secrets out of another process's memory, and the Trivy payload did exactly that to CI runners, covered below. A living-off-the-land binary (LOLBin) is a trusted system tool such as `bash`, `curl`, PowerShell, or `osascript` that malware uses instead of shipping its own binary.

## Can open source packages contain malware?

Yes, open source packages can contain malware, and new cases are reported every day. OpenSSF recorded 18,074 new reports in 2026 through October 29, between 480 and 4,763 a month. A [malicious package](https://socket.dev/glossary/malicious-package) is a published library whose code includes one of the behaviors above. It reaches developers in three main ways: an attacker publishes a new package with a convincing name, takes over a legitimate maintainer's account, or compromises the project's build and release pipeline.

The dataset counts need context. Of npm's 222,478 OpenSSF reports, 142,163 fall in November 2025, when [a flood of TEA protocol spam](https://socket.dev/blog/tea-protocol-spam-floods-npm-but-its-not-a-worm) of up to 150,000 packages received `MAL-` identifiers. We found no malicious code in those packages. The counts measure reports, not distinct payloads. Even without that month, npm has more reports than every other ecosystem combined.

The registry record of a removed malicious version is itself evidence. npm removes a malicious version but keeps its publish timestamp, so the attack window stays visible after the code is gone. Here is the Qix compromise as the registry recorded it, fetched on October 29, 2026 with npm 10.9.9:

```sh
$ npm view chalk@5.6.1 version
npm error code E404
npm error 404 No match found for version 5.6.1

$ npm view chalk time --json | grep '"5\.6\.'
  "5.6.0": "2025-08-17T07:27:47.572Z",
  "5.6.1": "2025-09-08T13:13:05.239Z",
  "5.6.2": "2025-09-08T14:47:54.486Z",

$ npm view debug time --json | grep '"4\.4\.'
  "4.4.1": "2025-05-13T20:56:36.431Z",
  "4.4.2": "2025-09-08T13:12:39.973Z",
  "4.4.3": "2025-09-13T17:25:19.732Z",

$ npm view socket.oi versions description --json
{
  "versions": [
    "0.0.1-security.8"
  ],
  "description": "security holding package"
}
```

`chalk@5.6.1` was published at 13:13:05 UTC, and a clean 5.6.2 followed 1 hour 35 minutes later. The malicious tarball can no longer be fetched, but a lockfile or build log that names 5.6.1 proves it was resolved. A wholly malicious package such as `socket.oi` is replaced by a `0.0.1-security` holding package, which is the registry's tombstone. A clean lockfile proves less than it seems. In [the axios compromise](https://socket.dev/blog/axios-npm-package-compromised), code fetched by `npx` or a global install never appeared in any project lockfile, a gap we traced in [the hidden blast radius of the axios compromise](https://socket.dev/blog/hidden-blast-radius-of-the-axios-compromise).

## Where package malware executes

A desktop trojan usually waits for someone to open it. Package malware has six execution points, because every stage of a dependency's life runs its code somewhere. The figure shows the stages in order, with a real case for each.

> Six stages where open source package malware executes: install, build, import, call, ship, and CI. Only the install stage is blocked by default in npm 12 and pnpm 10.

The figure, as text. Each stage runs dependency code under a different trigger:

| Stage | What triggers the code | Real case |
| --- | --- | --- |
| 1. Install | preinstall, install, and postinstall scripts run during npm install | @rspack/cli 1.1.7 downloaded XMRig from postinstall (December 2024) |
| 2. Build | setup.py in a Python sdist or build.rs in a Rust crate runs to build the package | crytic-compilers 0.3.11 ran s.exe from setup.py on Windows (June 2024) |
| 3. Import | Go init(), Python module top level, and Node module top level run when the dependency loads | shopsprint/decimal v1.3.3 starts a DNS TXT command loop at process start (August 2023 to May 2026) |
| 4. Call | A specific function runs the payload, sometimes only after a date or with a probability | sympy-dev ran its loader inside SymPy's groebner() (January 2026); shanhai666 packages trigger on database queries after 2027 |
| 5. Ship | The dependency is bundled into a web page and runs in visitors' browsers | chalk@5.6.1 and debug@4.4.2 rewrote crypto transactions in browsers (September 2025) |
| 6. CI | The dependency is a CI action or tool that runs with pipeline secrets | trivy-action tags read secrets from runner memory (March 2026) |

Install time is where most attacks run, and the defaults have finally changed. [pnpm 10](https://socket.dev/blog/pnpm-10-0-0-blocks-lifecycle-scripts-by-default) stopped running dependency [install scripts](https://socket.dev/glossary/postinstall-scripts) by default in January 2025. [npm 12](https://socket.dev/blog/npm-12), generally available since July 8, 2026, does the same. It also blocks implicit `node-gyp` builds, git dependencies, and remote tarball dependencies unless you approve them. Our npm 12 write-up put it plainly: "Almost every worm and credential stealer that hit the registry since late 2025 ran at install time." Default-on install scripts were a design mistake, and npm 12 and pnpm 10 have now corrected it. Blocking them covers stage 1 and the `node-gyp` part of stage 2, but pip still runs `setup.py` to build an sdist and cargo still runs `build.rs`. Stages 3 through 6 run with every install script disabled.

## How package malware differs from classic malware

Package malware inverts most of the assumptions classic defenses rest on.

Delivery needs no exploit and no phishing attachment. The victim's own tooling downloads the code on request, from a registry it trusts, over TLS.

Execution needs no social engineering after the dependency is chosen. The package manager, the build backend, the language runtime, or the bundler runs the code as part of normal work.

Privilege comes free. The code runs as the developer, the CI job, or the production service account, with every token in reach. The decimal backdoor analysis spells out the consequence: a CLI inherits the developer's credentials, and a CI job inherits its repository and deployment tokens.

Persistence needs no registry keys or launch agents, because every fresh install and every restart runs the code again.

Evasion is mostly unnecessary. The payload is source code that looks like the rest of the dependency, published as a new version that no scanner has seen yet.

The victim is also different. Classic malware targets the machine it lands on. Package malware often targets someone further down the chain: the website visitor whose wallet the Qix payload drained, or the company whose CI secrets the Trivy payload took.

## Why doesn't antivirus catch malware in packages?

Antivirus misses most package malware because the first stage is fresh source code, not a known binary. Signature matching needs a prior sample. A new malicious version of a package has none on the day it ships.

Attackers make sure of that. Socket's mid-year report describes one threat actor who used automation to publish 280 malicious npm packages in a single weekend. The same tooling can give every package its own obfuscation, so no two share a hash. Others keep the package nearly empty and fetch the real payload at run time. [The evm-units crate](https://socket.dev/blog/malicious-rust-crate-evm-units-serves-cross-platform-payloads) downloaded a script and ran it through `nohup bash` on Linux, `osascript` on macOS, and hidden PowerShell on Windows. Each of those is a LOLBin that endpoint tools see every day. [The sympy-dev package](https://socket.dev/blog/pypi-package-impersonates-sympy-to-deliver-cryptomining-malware) loaded an XMRig miner through `memfd_create` and ran it from an anonymous memory-backed file. When antivirus does fire, it fires on the second stage. One sympy-dev miner payload was detected by 22 of 64 VirusTotal engines. The loader that fetched it was a few lines of Python inside SymPy's polynomial routines.

Time and context gates defeat sandboxes. Most of the shanhai666 NuGet packages do nothing destructive until 2027 or 2028. The decimal backdoor runs only the commands its operator publishes in DNS. Socket's analysis found that the trojanized decimal release "has not been picked up by sandboxes or automated scanners" on the public surfaces it checked.

Advisory feeds have the same blind spot as signatures. [GitHub's advisory](https://github.com/advisories/GHSA-2x9r-6wxq-hrr7) for [plain-crypto-js](https://socket.dev/blog/axios-npm-package-compromised), the malicious dependency in the axios compromise, lists CWE-506, embedded malicious code, and no CVE. Its guidance is blunt: "Any computer that has this package installed or running should be considered fully compromised." Exceptions exist. [The tj-actions/changed-files compromise](https://socket.dev/blog/github-actions-supply-chain-attack-puts-thousands-of-projects-at-risk) received CVE-2025-30066. They are rare enough that CVE scanning alone misses most supply chain attacks.

What works is reading the package itself before it runs. [Malware detection](https://socket.dev/glossary/malware-detection) for dependencies combines static analysis of every new version, behavioral signals such as new network or shell access, and human review of what automation flags. Socket's AI scanner flagged all 84 compromised artifacts in [the TanStack compromise](https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack) within six minutes of publication in May 2026. Speed matters because CI jobs and developers with loose version ranges resolve a new version as soon as it is published.

## From stolen tokens to ransomware

Package malware is increasingly the first stage of an enterprise intrusion, not the last. A stolen npm token or CI secret is initial access, and initial access is what ransomware crews buy.

Ransomware-as-a-service (RaaS) splits the work. Core developers build the encryptor and leak infrastructure, and affiliates break in and deploy it for a share of the ransom. Big game hunting is the affiliate strategy of targeting large organizations that can pay large ransoms. A dedicated leak site is where a crew publishes stolen data from victims who refuse to pay, which turns a data breach into double extortion.

The supply chain now feeds that pipeline directly. In the Trivy compromise, the payload on GitHub-hosted runners found the `Runner.Worker` process through `/proc/*/cmdline`, read its memory regions through `/proc/<pid>/mem`, and searched them for secrets in the format the runner keeps in its heap. That is memory scraping, aimed at a CI job instead of a point-of-sale terminal. A week later, [posts attributed to the Vect RaaS group](https://socket.dev/blog/teampcp-partners-with-vect-targeting-oss-supply-chains) claimed a partnership with TeamPCP to "deploy ransomware across all affected companies." Vect advertises affiliate shares of up to 80 to 88 percent of the profits. Its claims are unverified. The intent is not new: [Black Basta's internal chat logs](https://socket.dev/blog/black-basta-dependency-confusion-ambitions-and-ransomware-in-open-source-ecosystems), leaked in February 2025, show that gang planning to test ransomware delivery through malicious npm and PyPI packages.

## What stops package malware, and what each control misses

No single control covers all six stages.

| Control | What it stops | What it misses |
| --- | --- | --- |
| Install scripts off by default (npm 12, pnpm 10) | Stage 1 payloads, where most recent worms and stealers run | Build, import, call, browser, and CI payloads |
| Lockfiles and pinned versions | Silent upgrades to a new malicious version during routine installs | npx, global installs, fresh resolves, and malicious versions you already pinned |
| Release cooldown (minimumReleaseAge in npm and pnpm, on by default in pnpm 11) | Short-lived malicious versions that are caught and pulled within the window | Sleepers like the decimal backdoor; it also delays urgent security patches |
| Provenance and trusted publishing | Tarballs built outside the project's real pipeline | Attackers who run code inside that pipeline |
| Antivirus and endpoint detection | Known second-stage binaries on managed machines | Fresh first stages, browser payloads, ephemeral CI runners |
| Pre-install package analysis | New malicious versions of any stage, judged on behavior before they run | Payloads fetched later, logic gated on dates or remote commands |

Verdict: turn on the defaults, because they are cheap. Install-script blocking costs a few approvals, and a [dependency cooldown](https://socket.dev/glossary/dependency-cooldown) costs a day of patch latency at the 1,440-minute default that [pnpm 11](https://socket.dev/blog/pnpm-11-adds-new-supply-chain-protection-defaults) ships. Together they remove the cheapest attacks. Do not mistake [package provenance](https://socket.dev/glossary/package-provenance) for a malware verdict. In the TanStack compromise, the malicious publishes authenticated through the project's own OIDC trusted-publisher binding. Then put a check that reads the code in front of every install, on developer machines, in CI, and in agent sandboxes.

That last check is a product category, and here is what ours does mechanically. [Socket Firewall Free](https://docs.socket.dev/docs/socket-firewall-free) wraps npm, yarn, pnpm, pip, uv, and cargo with an `sfw` prefix. It runs a local proxy that checks each requested artifact against Socket's API before download. It blocks only confirmed malware, warns on AI-detected potential malware, and does not block unscanned versions or packages already in a local cache.

## The open problem

The hardest malware to stop is code that is benign when inspected. A package that deletes nothing until 2028, or runs only the command an operator publishes next month, presents clean behavior to every analysis that runs today. Pre-install analysis can flag the capability: a date check next to `Process.Kill`, a DNS lookup feeding `exec.Command`. It cannot prove intent, and intent is the only thing that makes code malware. Better detection alone will not close that gap. The fix is giving dependencies less ambient authority, so a library that formats decimals cannot run commands at all.
