# Dependency Safety for Vibe-Coded Apps

*Published 2026-09-26 · Vibe Coding, Dependencies, Supply Chain, AI*

> AI agents casually npm install whatever makes the error go away — typosquats, dead packages, CVEs, bundle bloat. How to vet dependencies before you accept them.

Source: https://www.yashthakur.com/blog/vibe-coding-dependency-safety

---

**The short answer:** The fastest way a vibe-coded app gets compromised isn't your code — it's a dependency the agent casually `npm install`ed to make an error go away. Agents pull packages with lookalike typosquat names, abandoned libraries, known CVEs, and a 2MB dependency to do a one-line job. The fix is boring and total: **vet every package before you accept it, pin exact versions, commit the lockfile, and let a scanner fail the build.** Treat every dependency as code you are personally shipping, because you are.

Your own code gets reviewed. The 40 transitive packages an agent dragged in to satisfy one `import` do not — and that's where the risk lives. A dependency runs with the same privileges as the rest of your app: it can read your env vars, make network calls, and touch the filesystem. "The agent added it and the build passed" is not a security review. Here's the one you actually need.

## 1. Vet the package before you accept it

When an agent proposes a dependency, it's optimizing for "makes the code work," not "is this thing trustworthy." Three checks, every time, before the install lands:

- **Is it real?** Typosquatting is the oldest supply-chain trick — a malicious package named one character off a popular one (`lodahs` for `lodash`, `crossenv` for `cross-env`, `discordjs` for `discord.js`). An agent that half-remembers a name will install the wrong one without blinking. Confirm the exact name against the official docs or the real repo, not the agent's memory.
- **Is it maintained?** Recent releases, issues that get answered, a commit history that didn't stop two years ago. An abandoned package is an unpatched CVE waiting to happen and a dependency you'll be forced to rip out later.
- **Is it popular?** Download counts aren't proof of safety, but a package with millions of weekly downloads has thousands of eyes on it. A package with 40 downloads and no stars that the agent reached for is worth a hard look.

## 2. Pin exact versions — never open ranges

This is the single highest-leverage habit. Agents (and `npm install` defaults) write caret ranges like `^1.2.0`, which means "any 1.x newer than this." That's a standing invitation for a future install to silently pull a version you never reviewed — including the one an attacker published after compromising a maintainer's account.

```TXT
{
  "dependencies": {
    // ❌ Open range — a later install can resolve to ANY newer 4.x,
    //    including a compromised release you never saw.
    "left-pad": "^4.1.0",

    // ❌ Tilde is only marginally better — still floats the patch version.
    "date-fns": "~2.30.0",

    // ✅ Exact version — every install, everywhere, gets the bytes you reviewed.
    "zod": "3.23.8"
  }
}
```

Exact versions make your builds reproducible and your supply chain auditable: an upgrade becomes a deliberate, reviewable change in a diff, not something that happens behind your back at 2am on a CI runner.

## 3. Commit the lockfile, and watch for the typosquat

The lockfile (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`) records the exact resolved version *and an integrity hash* for every package and every transitive dependency. Commit it. Then `npm ci` on CI installs that exact tree and fails if anything doesn't match the hash — which is your tripwire against a tampered package.

And when you read a lockfile or a proposed `install`, read the name like an attacker wrote it:

```BASH
# A vibe-coding agent, asked to parse a date, runs one of these.
# Only one is the real library.

npm install moment       # ✅ the real, 20M-downloads-a-week package
npm install momnet       # ❌ typosquat — transposed letters
npm install moment-js    # ❌ typosquat — plausible suffix, not the real name

# The agent's output looks identical in all three cases: an import that "works".
# The difference only shows up when the malicious one runs its install script.
```

## 4. Scan in CI, prefer the platform, and watch the weight

Three more habits that close the loop:

- **Run `npm audit` (or Snyk / Dependabot / `osv-scanner`) in CI**, and make a high-severity finding *fail the build*. A vulnerability flagged in a pull request is a fix; the same one discovered in production is an incident.
- **Prefer the platform over a dependency.** Modern JS has `fetch`, `structuredClone`, `crypto.randomUUID()`, `Intl`, `Array.prototype.flat`. Agents reach for a package out of habit — `node-fetch`, a `uuid` lib, a left-pad — when the runtime already ships the capability. Every dependency you *don't* add is a supply-chain risk you never took.
- **Audit the bundle cost.** Pulling a 300KB date library to format one timestamp, or all of `lodash` for a single `get`, is bloat the agent won't think about. Check the weight (bundlephobia, `source-map-explorer`) and reach for a lighter alternative or a few lines of your own.

## The one-pass checklist

Before you accept a dependency a vibe-coding agent added, run this:

- [ ] Package name verified against the official source — not a typosquat
- [ ] Actively maintained (recent releases, answered issues)
- [ ] Popular enough to have real scrutiny (download counts)
- [ ] Pinned to an **exact** version, no `^` or `~`
- [ ] Lockfile committed; CI uses `npm ci` (not `npm install`)
- [ ] `npm audit` / a scanner runs in CI and fails on high-severity CVEs
- [ ] Could the platform or stdlib do this instead?
- [ ] Bundle cost checked — not a heavy lib for a trivial job

## Use agents and skills deliberately

Dependency safety is a place where pointing a **specialist agent** at the generalist's output pays off directly. The agent that wrote the feature was optimizing for "works"; a reviewer with a narrower brief catches the supply-chain mistakes it never considered.

- **A security-and-hardening skill** to audit new and existing dependencies for known CVEs, unmaintained packages, and suspicious names before you accept them.
- **A performance-optimization skill** to flag bundle bloat — a heavy library pulled in for a trivial task, or a dependency that duplicates something the platform already provides.
- A dependency/vulnerability scan wired into CI so a flagged package fails the build instead of reaching production.

Dependencies are the part of a vibe-coded app you didn't write but are fully responsible for. The agent treats `npm install` as free; you can't. Vet the package, pin the version, commit the lockfile, scan in CI — and the casual install stops being the weakest link in your supply chain.

This is one of the vibe-coding deep-dives — start from [the vibe-coding precautions overview](/blog/vibe-coding-precautions). It pairs closely with [security and networking precautions](/blog/security-networking-precautions), where the same scanner-in-CI habit lives, and [the frontend precautions](/blog/frontend-development-precautions), where bundle weight hits hardest.
