---
title: "How to tell if an npm package is malicious before you install it. Lazaretto"
description: "Signs an npm package is malicious before you install it: install scripts, credential reads, odd network calls and obfuscation. Plus how to automate it."
url: "https://lazaretto.dev/blog/how-to-tell-if-an-npm-package-is-malicious"
---

[Home](https://lazaretto.dev/) / [Blog](https://lazaretto.dev/blog) / 2026-07-16

# How to tell if an npm package is malicious before you install it

Most malicious npm packages give themselves away if you know where to look: install scripts, credential reads, odd network calls, obfuscation. Here is what to check, and how to automate it.

Most malicious npm packages give themselves away if you know where to look. The trouble is that nobody looks. `npm install` runs hundreds of times a day and reading every dependency by hand is not realistic. Here is what actually matters, and how to stop doing it by hand.

## The tells

A package that is up to something usually does at least one of these:

- **Runs code the moment you install.** Check the `scripts` field in package.json for `preinstall`, `install`, or `postinstall`. A line that pipes a download into a shell, runs `node -e` with inline code, or base64-decodes something is a flag.
- **Reads files it has no reason to touch.** `~/.ssh/id_rsa`, `~/.aws/credentials`, browser profile paths, environment variables full of tokens.
- **Sends data out.** A hardcoded IP or an odd domain next to an HTTP call, DNS lookups built from command output, a fetch to a pastebin.
- **Hides what it does.** Long base64 or hex blobs, dynamic `eval`, or a minified bundle shipped next to readable source.

## A package you trust can turn

The tells above assume a package written to be malicious. The harder case is a package that was fine for years and then was not. On 8 September 2025, version 5.6.1 of `chalk`, one of the most depended-on packages on npm, was published with malicious code added after the maintainer's account was compromised. It is listed in the OSV and OpenSSF malicious-packages advisories as `MAL-2025-46969`, which says a machine with it installed should be treated as fully compromised. The versions on either side of it are ordinary.

The question is whether this exact version is malicious right now. You can check that for any npm package with one GET, no key:

```
curl -s https://lazaretto.dev/v1/attestations/npm:chalk@5.6.1
#   read identity_check.listed_as_malware
```

That answer comes from the published advisory corpus, which we sync daily. It matches the name and version and does not read the code. For something you already depend on, register your dependency set once with `/v1/watch` and read it back later to learn whether any of it has been listed as malware since. A one-off check cannot tell you that a package turned after you installed it.

## Automate it

Reading for all of that by hand does not scale. Lazaretto does it for you. Point it at a package and it pulls the files into a sandbox, never runs them, and checks for exactly these patterns plus a match against known-bad hashes. You get a verdict and the exact line that tripped it.

```
curl -s https://lazaretto.dev/v1/known-bad/<sha256>        # free
curl -s -X POST https://lazaretto.dev/v1/scan -H 'content-type: application/json' \
  -d '{"target":{"type":"npm_package","ref":"some-pkg@1.0.0"},"depth":"full"}'
```

The known-bad lookup is free. A full scan is a few cents over x402 or with a prepaid key. See the [rule catalog](https://lazaretto.dev/v1/rules).

[Check your lockfile for known malware](https://lazaretto.dev/check/lockfile). Free, no card.

Lazaretto is the pre-install checkpoint agents call themselves. [Try it](https://lazaretto.dev/#try) · [pricing](https://lazaretto.dev/pricing) · [connect your agent](https://lazaretto.dev/agents).

---

Machine-readable index: https://lazaretto.dev/llms.txt. OpenAPI: https://lazaretto.dev/openapi.json. MCP endpoint: https://lazaretto.dev/mcp. Any page on this site is available as markdown by adding .md to its path.
