continuedev / continuedev/continue

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

Open
#12,573 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:tools javascript kind:enhancement
Dominant language
TypeScript
Stars
36k
Forks
5.4k
PR merge metrics
No merged PRs in 30d

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in evaluateTerminalCommandSecurity.ts by reading the existing isHighRiskPackageManager and isHighRiskCommand checks. Run the package's Vitest suite and tsc --noEmit, then verify the listed npm-ecosystem install and runner cases, including the --prefix axio false-positive guard. Done means the offline checker is integrated, escalates matches to allowedWithPermission, and the full suite remains green.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, devtools, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.