AI coding agents and supply chain risk: how to verify dependencies before merging

AI Coding Agents and Supply Chain Risk: How to Verify Dependencies Before Merging

When an AI coding agent adds a dependency to your project, it does not tell you whether that package is maintained, whether it has known vulnerabilities, or whether it was published by a trustworthy author. It just adds the line to your requirements, package.json, or go.mod — and if you merge without checking, you have just given a stranger’s code a direct path into your production system.

Supply chain attacks on software dependencies are not theoretical. In the last few years, we have seen:

  • typosquatting attacks where malicious packages mimic popular ones with slight name variations
  • dependency confusion attacks where internal package names are registered on public registries with malicious payloads
  • maintainer compromise where legitimate packages are hijacked to deliver malware
  • protestware where maintainers intentionally break their own packages to make a statement

AI coding agents make all of these risks worse because they add dependencies faster than most teams can verify them. This article gives you a practical framework for catching dependency risk before it reaches production — whether you use Copilot, Cursor, Claude Code, or any other AI coding tool.

Why AI agents make dependency risk worse

AI coding agents do three things that increase supply chain risk:

1. They add dependencies you did not ask for

You ask an AI agent to „add date formatting” and it installs moment (deprecated, 300KB), date-fns (tree-shakeable, modern), and dayjs (lightweight alternative) — then uses whichever one it prefers. You may not even notice the extras until you audit package.json or requirements.txt.

In one real-world pattern, developers asked AI agents to fix a small bug and received a PR that added 3-5 new dependencies, none of which were necessary for the fix. The agent had learned from training data that included these imports and „helpfully” included them.

2. They cannot distinguish between a well-maintained package and a compromised one

AI models do not check npm download counts, GitHub star trends, last-commit dates, or known CVEs. They pattern-match on names and import statements. If event-stream appeared in training data, the agent will suggest it — even though that package was famously compromised in 2018.

3. They create transitive dependency trees you cannot see

When an agent adds one package, it pulls its entire dependency tree. A single line in package.json can bring in 50+ transitive dependencies. Most developers never check beyond the direct dependency. The agent certainly does not.

The dependency verification checklist for AI-generated code

Before you merge any AI-generated change that adds or modifies dependencies, run this checklist. It takes under 15 minutes for most PRs and catches the most common supply chain risks.

Check 1: Did the AI add any dependencies you did not explicitly request?

What to look for:

  • Compare the dependency diff against the task description
  • Look for packages that were not mentioned in your request
  • Check for version pinning versus loose ranges (^1.2.3 vs >=1.0.0)

Quick test:

# For Node.js projects: show what changed in package.json
git diff main...HEAD -- package.json package-lock.json

# For Python projects: show what changed in requirements
git diff main...HEAD -- requirements.txt setup.py pyproject.toml Pipfile

# For Go projects
git diff main...HEAD -- go.mod go.sum

If the diff shows dependencies that are not obviously required for the task, flag them. AI agents frequently add „helper” packages that introduce unnecessary attack surface.

When to escalate: If the agent added more than 2-3 unexpected dependencies, reject the change and ask for a minimal implementation that uses existing packages or the standard library.

Check 2: Is each added package real, maintained, and from a trusted source?

What to verify for each new dependency:

  1. Does the package actually exist on the registry? Typosquatting attacks use names that look similar to popular packages. Check the exact spelling against npmjs.com, pypi.org, or the relevant registry.
  1. When was it last updated? A package with no updates in 2+ years may be abandoned, which means unpatched vulnerabilities and no maintainer response to security reports.
  1. How many downloads does it have? A package with fewer than 1,000 weekly downloads on npm (or equivalent on other registries) is risky. Low download counts mean few eyes on the code and slow vulnerability discovery.
  1. Does it have known security advisories? Check npm audit, pip audit, or GitHub Dependabot alerts for known CVEs.
  1. Who maintains it? Packages maintained by a single unknown developer are higher risk than those maintained by a recognized organization or a team with a track record.

Quick verification script (Node.js):

# Check if package exists and get basic stats
npm view  description version repository
npm view  time --json | head -5

# Check for known vulnerabilities
npm audit --production

Quick verification script (Python):

# Check package metadata
pip index versions 

# Check for known vulnerabilities
pip-audit --desc

# Or use safety check
safety check --json

Check 3: Are there transitive dependency risks you cannot see?

Direct dependencies are only the surface. The real risk is in the dependency tree below.

What to do:

  • Run a dependency tree audit before and after the AI-generated change
  • Compare the trees to identify new transitive dependencies
  • Check if any transitive dependency is known-vulnerable or unmaintained

Quick test:

# Node.js: show the full dependency tree
npm ls --all --long

# Python: show dependency tree
pipdeptree

# Go: show module dependencies
go mod graph

When to escalate: If the agent’s change adds more than 10 transitive dependencies, consider whether the functionality can be achieved with a lighter alternative or standard library code.

Check 4: Are dependency versions pinned or loose?

AI agents often generate loose version ranges because training data contains many examples of ^version and >=version patterns. Loose ranges are convenient but dangerous:

  • ^1.2.3 allows any 1.x.y version — including a future 1.3.0 that introduces a vulnerability
  • >=1.0.0 allows any version — including a malicious 99.0.0 published by a compromised maintainer
  • * or latest allows any version, including breaking changes and compromised releases

Best practice: Pin exact versions in production dependencies. Use lockfiles (package-lock.json, Pipfile.lock, go.sum) and commit them to version control.

Quick test:

# Check for loose version ranges in requirements.txt
grep -E '(>=|~=|>|<|\*)' requirements.txt

# Check for unpinned dependencies in package.json
cat package.json | python3 -c "
import json, sys, re
data = json.load(sys.stdin)
for dep_type in ['dependencies', 'devDependencies']:
    for name, ver in data.get(dep_type, {}).items():
        if ver in ['latest', '*'] or ver.startswith('>=') or ver.startswith('^'):
            print(f'{dep_type}: {name}={ver} (loose range)')
"

Check 5: Did the AI modify lockfiles or checksums in unexpected ways?

Lockfiles and checksum files are your integrity verification layer. If an AI agent modifies them without a clear reason, it may be:

  • Downgrading a dependency to a vulnerable version
  • Removing integrity checks
  • Replacing checksums to match a compromised package

What to check:

  • package-lock.json changes that downgrade version numbers
  • Pipfile.lock changes that remove hash entries
  • go.sum changes that modify existing checksums
  • Any removal of integrity fields (integrity in npm, --hash in pip)

Quick test:

# Check if integrity hashes were removed from package-lock.json
git diff main...HEAD -- package-lock.json | grep -c "integrity" 

# Check if hashes were removed from Pipfile.lock
git diff main...HEAD -- Pipfile.lock | grep -c "sha256:"

# Check go.sum for modified checksums (not just additions)
git diff main...HEAD -- go.sum | grep "^-"

Check 6: Can you generate an SBOM (Software Bill of Materials) for this change?

An SBOM is a list of all components in your software, including version numbers and dependency relationships. It is becoming a compliance requirement in many industries and is essential for incident response.

How to generate an SBOM:

# Node.js
npm sbom --sbom-type spdx > sbom-spdx.json

# Python (using cyclonedx-bom)
pip install cyclonedx-bom
cyclonedx-py requirements -i requirements.txt -o sbom.xml

# Go
go mod graph | cyclonedx-go -o sbom.json

Even if you do not currently need an SBOM for compliance, having one means you can quickly answer „are we affected by vulnerability X?” when a new supply chain attack is disclosed.

Practical workflow: Dependency verification in your review process

Here is how to integrate these checks into your existing code review workflow:

Before the review

  1. Generate the dependency diff automatically. Add a CI step that compares package.json, requirements.txt, or go.mod before and after the PR.
  1. Run automated vulnerability scanning. Use Dependabot, Snyk, npm audit, pip-audit, or equivalent tools as a required CI check.
  1. Flag any PR that adds more than N new dependencies. Set a threshold (we recommend 3-5 for small teams) and require explicit justification for exceeding it.

During the review

  1. Verify each new dependency against the checklist above. For AI-generated PRs, this is not optional — the agent did not verify them for you.
  1. Check if the dependency is actually necessary. Can the functionality be achieved with the standard library or an existing dependency?
  1. Look for alternative packages that are more maintained, lighter, or more widely trusted. AI agents often suggest the first package they learned about, not the best one.

After the review

  1. Update your SBOM with the new dependencies.
  1. Add the dependency to your internal allowlist if you maintain one.
  1. Set up monitoring for vulnerability advisories on the new package.

CI gate: Automated dependency verification for AI-generated PRs

For teams that use CI, here is a GitHub Actions workflow that runs dependency checks automatically:

# .github/workflows/dependency-gate.yml
name: Dependency Verification Gate

on:
  pull_request:
    paths:
      - 'package.json'
      - 'package-lock.json'
      - 'requirements.txt'
      - 'Pipfile.lock'
      - 'go.mod'
      - 'go.sum'

jobs:
  dependency-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - name: Check for new dependencies
        run: |
          # Count new dependencies added in this PR
          NEW_DEPS=$(git diff origin/main...HEAD -- package.json | grep -c '^\+' | head -1 || echo "0")
          echo "New dependency additions detected: $NEW_DEPS"
          if [ "$NEW_DEPS" -gt 5 ]; then
            echo "::warning::More than 5 dependency additions — please verify each one"
          fi
      
      - name: Run npm audit
        if: hashFiles('package-lock.json') != ''
        run: npm audit --production --audit-level=high
        continue-on-error: false
      
      - name: Run pip-audit
        if: hashFiles('requirements.txt') != ''
        run: |
          pip install pip-audit
          pip-audit --desc -r requirements.txt
        continue-on-error: false
      
      - name: Check for loose version ranges
        run: |
          echo "Checking for loose version constraints..."
          # Node.js
          if [ -f package.json ]; then
            LOOSE=$(cat package.json | python3 -c "
          import json, sys
          data = json.load(sys.stdin)
          loose = []
          for dep_type in ['dependencies', 'devDependencies']:
              for name, ver in data.get(dep_type, {}).items():
                  if ver in ['latest', '*'] or ver.startswith('>='):
                      loose.append(f'{name}={ver}')
          print('\n'.join(loose))" 2>/dev/null || echo "")
            if [ -n "$LOOSE" ]; then
              echo "::warning::Loose version ranges found: $LOOSE"
            fi
          fi
          # Python
          if [ -f requirements.txt ]; then
            LOOSE_PY=$(grep -cE '(>=|~=|>|<|\*)' requirements.txt || echo "0")
            if [ "$LOOSE_PY" -gt 0 ]; then
              echo "::warning::$LOOSE_PY loose version ranges found in requirements.txt"
            fi
          fi

This gate does three things:

  1. Warns when more than 5 dependencies are added in a single PR
  2. Fails the build on high-severity vulnerabilities
  3. Flags loose version ranges that could allow supply chain attacks

Real-world examples of dependency risk in AI-generated code

Example 1: The "helper" package that was never needed

A developer asked an AI agent to add input validation to a Flask endpoint. The agent's response included:

+ from flask_wtf.csrf import CSRFProtect
+ from werkzeug.security import generate_password_hash
+ from markupsafe import escape
+ import bleach

The task only needed markupsafe.escape. The agent added bleach (a full HTML sanitizer, unnecessary for plain escaping), flask_wtf (adds CSRF protection, not requested), and werkzeug.security (password hashing, not related to input validation). Each unnecessary dependency expands the attack surface.

Example 2: Typosquatting close call

An AI agent suggested importing reqeusts instead of requests. The typo is one transposed letter, and reqeusts is exactly the kind of name a typosquatter would register. If merged without verification, it could execute arbitrary code at import time.

Example 3: The deprecated dependency

An AI agent suggested using pycrypto for encryption. This package has been unmaintained since 2013 and has multiple known CVEs. The correct modern alternative is cryptography. But the agent's training data still contains many examples of pycrypto imports, so it keeps suggesting it.

How CodeRiskTools helps with dependency verification

The CodeRiskTools review kit includes a structured dependency verification section as part of the pre-merge checklist. The Basic kit covers the five-check review pass that includes a security check for dependency risks. The Pro kit adds:

  • Expanded risk review prompts specifically for dependency and supply chain verification
  • Risk scoring workflow that rates dependency additions by severity (Low through Critical)
  • Client-ready summaries that document dependency review findings for stakeholders

If your team is regularly reviewing AI-generated PRs that add dependencies, the structured prompts and scoring workflow help you catch risks systematically instead of hoping you notice them.

See Basic details — five-check review pass including dependency verification

See Pro details — expanded dependency prompts, risk scoring, and client-ready summaries

Key takeaways

  1. AI agents add dependencies without verification. They pattern-match on training data, not on package safety metrics. Every AI-added dependency needs human review.
  1. Check all five dimensions: necessity, maintenance status, transitive tree, version pinning, and lockfile integrity. Missing any one of these leaves a gap.
  1. Pin your versions. Loose version ranges are an invitation for supply chain attacks. Use exact versions and lockfiles in production.
  1. Automate what you can. CI gates for dependency count, vulnerability scanning, and loose version detection catch the easy stuff. Human review catches the rest.
  1. Generate and maintain an SBOM. When a supply chain vulnerability is disclosed, you need to answer "are we affected?" in minutes, not days.
  1. Treat every AI-added dependency as untrusted until verified. The agent did not check it. That means you have to.

Related reading

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola oznaczone są *.

*
*
Możesz użyć następujące tagi i atrybuty <abbr title="HyperText Markup Language">HTML</abbr>: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Wczytywanie, proszę czekać...
WRÓĆ NA GÓRĘ