← All posts
dependency confusionsupply chain attackvibe codingAI coding securitynpm security

Vibe-Code Dependency Confusion: Stop Supply Chain Attacks

O

OverMCP Team

Quick answer

Dependency confusion attacks exploit package managers (npm, PyPI, etc.) by tricking your app into installing a malicious package from a public registry instead of your private one. Vibe-coded apps are especially vulnerable because AI tools often generate package.json files with typos or missing scope markers, making it easy for attackers to publish similarly named packages. To prevent this, always scope your private packages, pin versions, and scan your dependencies with a tool like OverMCP's free AI app security scanner.

What is dependency confusion and why vibe-coded apps are at risk

Dependency confusion (also called a supply chain substitution attack) happens when a package manager resolves a dependency name to a public registry instead of your private one. For example, if your package.json has "my-internal-lib": "^1.0.0" but you forgot to scope it (e.g., @company/my-internal-lib), npm will look for my-internal-lib on the public npm registry. An attacker can publish a malicious package with that exact name, and your next npm install will pull it in.

Vibe-coded apps—built quickly with tools like Cursor, Bolt.new, v0, Lovable, and Replit Agent—are particularly susceptible. AI coding assistants often generate dependency lists from vague prompts, leading to:

  • Missing scopes: The AI forgets to add @your-org/ before a private package name.
  • Typos: A misnamed package that an attacker can squatt.
  • Overly broad versions: Using ^ or * instead of exact versions, allowing the attacker's version to be installed.
  • What to check first

    Before you deploy or even run npm install on a vibe-coded app, run through this checklist:

  • [ ] Audit all dependencies in package.json, requirements.txt, Gemfile, etc. Look for any package name that could be confused with a public one.
  • [ ] Check for missing scopes: If you have any private packages, ensure they are scoped (e.g., @myorg/package-name).
  • [ ] Verify package names against public registries: Search npm, PyPI, or RubyGems for each dependency. If a package exists publicly but you intended it to be private, you have a problem.
  • [ ] Pin exact versions: Replace ^1.0.0 with 1.0.0 (no caret or tilde) for all private dependencies.
  • [ ] Use a lockfile: Ensure package-lock.json or yarn.lock is committed and reviewed.
  • [ ] Run a security scan: Use a tool like OverMCP's secret leak scanner to also check for leaked credentials that could be used to publish malicious packages.
  • Step-by-step fix

    Here's how to secure your vibe-coded app against dependency confusion.

    1. Scope all private packages

    Change this:

    "dependencies": {
      "internal-auth": "^1.0.0"
    }

    To this:

    "dependencies": {
      "@mycompany/internal-auth": "1.0.0"
    }

    2. Configure your registry in .npmrc

    Create or update .npmrc in your project root:

    registry=https://registry.npmjs.org/
    @mycompany:registry=https://npm.pkg.github.com/
    //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

    This tells npm to use the public registry for all packages except those scoped under @mycompany, which should be fetched from GitHub Packages.

    3. Pin exact versions

    Remove version ranges for private packages. Use "1.0.0" not "^1.0.0".

    4. Use overrides to block public lookups

    In package.json, add an overrides section to force resolution of specific packages:

    "overrides": {
      "internal-auth": "npm:@mycompany/internal-auth@1.0.0"
    }

    This only works if you have control over all package names.

    5. Run a pre-install script

    Add a script to package.json that checks for un-scoped packages:

    "scripts": {
      "preinstall": "node -e \"const pkg=require('./package.json'); Object.keys(pkg.dependencies||{}).forEach(d=>{if(!d.startsWith('@')){console.error('Unscoped dependency: '+d); process.exit(1)}})\""
    }

    6. Scan regularly with OverMCP

    After fixing, set up continuous security monitoring to catch new dependency confusion risks as your app evolves.

    Common mistakes

    Mistake 1: Trusting AI-generated package names blindly

    AI tools often invent package names or misspell them. For example, Cursor might suggest "auth-helper" when the real internal package is "@acme/auth-helper". An attacker can publish auth-helper on npm, and your next deploy pulls it in.

    Fix: Always verify every dependency name against your internal registry and public registries.

    Mistake 2: Using `npm install <package>` without the scope

    When adding a private package manually, it's easy to forget the @scope/ prefix. Run npm install @mycompany/package-name instead.

    Mistake 3: Not using a lockfile

    Lockfiles ensure the exact same versions are installed every time. If you have a lockfile but didn't pin versions, an attacker could publish a newer version that gets resolved first.

    Fix: Always commit package-lock.json or yarn.lock and review changes carefully.

    Mistake 4: Assuming private packages are safe because they're not public

    If your private package is hosted on a private registry (like npm Pro or GitHub Packages), but an attacker publishes a public package with the same name, the package manager may choose the public one if the registry configuration is wrong.

    Fix: Use scopes and explicit registry configuration in .npmrc.

    Mistake 5: Ignoring similar package names on public registries

    Attackers often use typosquatting: my-interna-lib vs my-internal-lib. AI-generated code can introduce such typos.

    Fix: Run a tool like OverMCP's security headers checker to scan your app, but also manually search for similar package names.

    How OverMCP helps

    OverMCP is built for indie makers who ship fast with AI. Our free AI app security scanner checks your dependencies for known vulnerabilities and dependency confusion risks. You can also connect your Vercel project to get continuous monitoring every time you deploy. No complex setup—just scan and fix.

    FAQ

    What is dependency confusion in simple terms?

    Dependency confusion is when your app accidentally installs a malicious public package because the package manager can't tell the difference between a private package and a public one with the same name. Attackers exploit this by publishing packages with names they know you use internally.

    How do I know if my vibe-coded app has a dependency confusion vulnerability?

    Check your package.json for any dependency that doesn't start with a scope (like @myorg/) and that also exists on the public npm registry. If you find one, you are vulnerable. Also run a lockfile diff—if a package name changes, investigate.

    Can OverMCP detect dependency confusion?

    Yes. OverMCP's secret leak scanner and continuous security monitoring can flag dependencies that match public packages. We're adding dedicated dependency confusion detection soon. In the meantime, run the checklist above.

    Is your app secure?

    Free scan in 30 seconds. No signup needed.

    Scan My App Free