Skip to content

terminal-security: package-manager rule flags installs but not typosquat targets (e.g. npm install lodahs) #12573

Description

@AyoubTadlaoui

Summary

@continuedev/terminal-security already gates package installs behind permission via isHighRiskPackageManager (it recognises npm/yarn/pnpm install/add/i). That rule answers "is this an install?" but not "what is being installed?". A command like npm install lodahs (one edit from lodash) is treated identically to npm install lodash: both land at allowedWithPermission, with no signal that the target name is a likely typosquat. Runner forms such as npx expres aren't covered by the package-manager list at all.

Typosquatting is one of the most common npm supply-chain attack vectors, and an AI agent driving the terminal is exactly the actor most likely to fat-finger or hallucinate a package name. The evaluator is the right seam, because it is the choke point that decides whether a terminal command auto-runs.

Gap (reproducible, offline)

  • npm install lodahs — no distinction from a legitimate install; a reviewer sees no "this looks like a typosquat of lodash" signal.
  • npx expresnpx/bunx aren't in the package-manager list, so the typosquat target gets no dedicated treatment.
  • pnpm dlx expres, yarn add lodahs, bun add lodahs — same gap across managers and runners.

Proposal

Add a sibling, pure/offline checker in the same seam that detects npm-ecosystem installs (and npx/bunx/dlx/exec runner targets) of a name exactly one edit away from a curated set of popular packages, and wire it into the existing isHighRiskCommand aggregator so a hit escalates the policy to allowedWithPermission (most-restrictive-wins). It never hard-denies; it only asks the human.

Design:

  • Pure/offline/deterministic. No network, no filesystem, no new runtime dependencies.
  • Gate: Optimal String Alignment (restricted Damerau-Levenshtein) distance == 1 and the matched popular name length > 4 (short names like vue produce too many false positives).
  • Hardening to avoid false positives: sub-command splitting on ;/&&/||/|/&/newlines, env-assignment + wrapper prefixes (sudo, env FOO=bar), path-prefix on the binary, leading global options before the subcommand, value-taking install flags (so npm install --prefix axio lodash does not flag axio, which is a --prefix value, not a package), quote stripping, and @scope/pkg@version normalization.

I have a working implementation + vitest suite ready (45 new cases including the --prefix axio false-positive guard; the package's full suite stays green at 269 passing; tsc --noEmit clean) and proposed the same check upstream in Goose: aaif-goose/goose#9642. Would the maintainers be open to it living next to the existing isHighRisk* checks in evaluateTerminalCommandSecurity.ts? Happy to open the PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:toolsRelates to tool usagejavascriptPull requests that update Javascript codekind:enhancementIndicates a new feature request, imrovement, or extension

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions