Skip to content

13.1 Dependency Selection Criteria and Vetting

Every dependency you add is a trust decision with ongoing consequences. That npm package solving today's problem becomes tomorrow's vulnerability to patch, license to comply with, and update to manage. Organizations that treat dependency selection casually accumulate technical debt and supply chain risk; those with systematic vetting processes make informed decisions that balance development velocity with long-term maintainability.

This section establishes a framework for evaluating dependencies before adoption, covering security, maintenance, functionality, and licensing criteria—with special attention to validating dependencies suggested by AI coding assistants.

Establishing a Dependency Evaluation Process

Dependency vetting should be proportionate to risk. A utility library for formatting dates warrants different scrutiny than a cryptographic library handling authentication. Define a tiered process that applies appropriate rigor based on context.

Tiered Evaluation Approach:

Tier Criteria Evaluation Depth
Critical Security-sensitive, high privilege, widely used Full evaluation, security review
Standard Typical application dependencies Standard checklist, documented decision
Lightweight Dev-only tools, low-risk utilities Quick check, minimal documentation

Evaluation Process Flow:

┌─────────────────────────────────────┐
│  1. Identify Need                   │
│  - What problem does this solve?    │
│  - Is a dependency necessary?       │
└─────────────┬───────────────────────┘
┌─────────────────────────────────────┐
│  2. Discover Options                │
│  - Search registries and resources  │
│  - Identify alternatives            │
│  - Include "build vs. depend" option│
└─────────────┬───────────────────────┘
┌─────────────────────────────────────┐
│  3. Assess Risk Tier                │
│  - Security sensitivity?            │
│  - Production vs. dev-only?         │
│  - Direct vs. transitive exposure?  │
└─────────────┬───────────────────────┘
┌─────────────────────────────────────┐
│  4. Evaluate Against Criteria       │
│  - Security                         │
│  - Maintenance                      │
│  - Functionality                    │
│  - Licensing                        │
└─────────────┬───────────────────────┘
┌─────────────────────────────────────┐
│  5. Compare Alternatives            │
│  - Which option scores best?        │
│  - Are trade-offs acceptable?       │
└─────────────┬───────────────────────┘
┌─────────────────────────────────────┐
│  6. Document Decision               │
│  - Why this dependency?             │
│  - What risks were accepted?        │
│  - Who approved?                    │
└─────────────────────────────────────┘

Decision Documentation:

Record dependency decisions for future reference:

# Dependency Decision: [package-name]

**Date:** 2024-01-15
**Requester:** @developer
**Reviewer:** @security-team

**Purpose:** [What does this dependency provide?]

**Alternatives Considered:**
- Alternative A: [Why not selected]
- Alternative B: [Why not selected]
- Build in-house: [Why not selected]

**Evaluation Summary:**
- Security: [Pass/Concern/Fail]
- Maintenance: [Pass/Concern/Fail]
- Licensing: [Pass/Concern/Fail]

**Risks Accepted:** [Document any concerns that were accepted]

**Decision:** [Approved/Rejected]
**Approver:** @approver

Security Criteria

Security evaluation determines whether a dependency is likely to introduce vulnerabilities or become a supply chain attack vector.

Security Evaluation Checklist:

Criterion What to Check Red Flags
Vulnerability history CVE count, severity, response time Many high-severity CVEs, slow patching
Current vulnerabilities Known unpatched CVEs Any critical/high unpatched
Security policy SECURITY.md presence, disclosure process No security contact
Security practices Code signing, 2FA for maintainers Anonymous maintainers, no signing
Dependency depth Transitive dependency count Hundreds of transitive deps
OpenSSF Scorecard Automated security score Score < 5
Package age Time since creation Very new (< 6 months)

Vulnerability Assessment:

Check multiple sources for vulnerability information:

# npm
npm audit

# Python
pip-audit

# Check OpenSSF Scorecard
scorecard --repo=github.com/owner/repo

# Check deps.dev for vulnerability data
# Visit: https://deps.dev/npm/[package-name]

Security Practice Indicators:

Strong security practices include:

  • SECURITY.md file: Clear vulnerability reporting process
  • Security advisories: History of responsible disclosure
  • Signed releases: Cryptographic signatures on releases
  • 2FA enforcement: For maintainer accounts (visible via Scorecard)
  • Branch protection: Required reviews for code changes
  • Dependency updates: Automated (Dependabot, Renovate)

Supply Chain Risk Factors:

Consider supply chain-specific risks:

  • Install scripts: Does the package run code on install?
  • Native code: Does it compile or include native binaries?
  • Dynamic loading: Does it download code at runtime?
  • Network access: Does it make unexpected network calls?
  • Maintainer count: Single maintainer = higher bus factor risk

Maintenance Criteria

Maintenance health indicates whether a project will continue to receive updates, security patches, and community support.

Maintenance Health Indicators:

Indicator Healthy Signal Concern Signal
Last release Within 12 months > 2 years ago
Last commit Within 6 months > 1 year ago
Issue response Median < 7 days Median > 30 days
PR merge time Median < 30 days PRs languishing months
Open issues Reasonable backlog Hundreds ignored
Contributors Multiple active Single contributor
Stars/usage Appropriate for type Very low for claimed purpose

Checking Maintenance Health:

# GitHub API for recent activity
gh api repos/{owner}/{repo}/stats/commit_activity

# npm download trends
npx npm-stat-api [package-name]

# Check libraries.io for maintenance score
# Visit: https://libraries.io/npm/[package-name]

Context Matters:

Interpret maintenance signals in context:

  • Mature, stable packages: Low activity may be appropriate (e.g., left-pad doesn't need frequent updates)
  • Active development: Expect regular commits and releases
  • Security-sensitive: Demand responsive maintenance regardless of maturity

Organizations increasingly reject dependencies based on maintainer responsiveness rather than just existing vulnerabilities—a package whose maintainer hasn't responded to issues for 18+ months creates unacceptable risk that security patches won't arrive when needed.

Functionality Criteria

Does the dependency provide what you need without unnecessary bloat? Excess functionality increases attack surface and maintenance burden.

Feature-to-Dependency Ratio:

Evaluate whether the functionality justifies the dependency:

Question Concern If...
How much of this package will we use? Less than 20% of functionality
Could we implement this ourselves? Simple functionality, few lines of code
Does it pull in many transitive deps? 50+ transitive dependencies for simple task
Does it include unneeded capabilities? Network access for local-only task

Example Evaluation:

Considering a date formatting library:

Need: Format dates in ISO format

Option A: moment.js
- Size: 290KB
- Transitive deps: 0 (but large)
- Features: Extensive date manipulation
- Verdict: Overkill for formatting only

Option B: date-fns
- Size: Modular (import what you need)
- Transitive deps: 0
- Features: Individual functions
- Verdict: Better fit (import only format)

Option C: Native JavaScript
- Date.toISOString() built-in
- Zero dependencies
- Verdict: Best if this meets requirements

The "One-Liner" Test:

Before adding a dependency, ask:

  1. Could I write this in < 50 lines of code?
  2. Is the functionality truly complex enough to warrant external code?
  3. Would maintaining my implementation be easier than managing the dependency?

Sometimes the answer is still "use the dependency"—battle-tested code beats homegrown bugs. But the analysis ensures conscious decision-making.

Licensing Criteria

License compatibility determines whether you can legally use the dependency in your context. (See Section 12.5 for detailed license discussion.)

Quick License Compatibility Reference:

Your Project Can Use
Proprietary/Commercial MIT, Apache 2.0, BSD, ISC
Proprietary/Commercial LGPL (with care), MPL (file-level)
Proprietary/Commercial ⚠️ GPL, AGPL generally incompatible
Open Source (permissive) Any OSI-approved license
Open Source (copyleft) Must comply with copyleft terms

License Checks:

# npm
npx license-checker --summary

# Python
pip-licenses

# Multi-ecosystem
licensee detect .

License Red Flags:

  • No license: Legally ambiguous; avoid
  • Custom license: Requires legal review
  • License mismatch: Package.json says MIT, file says GPL
  • Transitive copyleft: Dependencies bring copyleft obligations

Alternatives Assessment

Never evaluate a dependency in isolation. Compare against alternatives to ensure you're making the best choice.

Discovery Techniques:

  1. Registry search: npm search, PyPI search for similar packages
  2. Awesome lists: Curated lists (e.g., awesome-python, awesome-node)
  3. Stack Overflow: See what others use for similar problems
  4. deps.dev: Related packages and dependency information
  5. npm-compare: Side-by-side comparison (for npm)
  6. Libraries.io: Cross-ecosystem search

Comparison Framework:

Criterion Option A Option B Option C
Security score 7.2 8.5 6.1
Maintenance Active Active Stale
Size (KB) 150 80 200
Transitive deps 12 5 45
License MIT Apache 2.0 GPL-3.0
Documentation Good Excellent Poor
Decision

The "No Dependency" Option:

Always include "don't add a dependency" as an alternative:

  • Implement the functionality yourself
  • Use platform/language built-ins
  • Restructure to avoid the need

This isn't always the right choice, but it should always be considered.

The Hidden Cost of Dependencies

Dependencies have ongoing costs beyond initial integration.

Hidden Cost Calculation:

Cost Category Estimate
Integration Hours to add and configure
Learning Time to understand API and patterns
Updates Hours/year to update and test
Vulnerabilities Hours/year to triage and remediate
Transitive maintenance Costs multiplied by transitive deps
Breaking changes Periodic major version migration
Abandonment risk Potential replacement cost if abandoned

Example Cost Estimate:

Adding a dependency with 50 transitive dependencies:

Integration:                    4 hours
Annual updates (51 packages):   8 hours
Vulnerability triage (2/year):  4 hours
Major version update (1/3 year): 3 hours

Annual ongoing cost: ~15 hours

Over 5 years: 4 + (15 × 5) = 79 hours

This doesn't make dependencies wrong—it makes the cost visible for informed decisions.

Dependency Budget:

Some organizations set dependency budgets:

  • Maximum direct dependencies per project
  • Maximum transitive dependency depth
  • Required justification above thresholds

These aren't hard rules but encourage conscious decisions.

Validating AI-Suggested Dependencies

AI coding assistants frequently suggest dependencies, sometimes hallucinating packages that don't exist (see Book 1, Section 10.2). Validate AI suggestions before acting on them.

AI-Specific Vetting Steps:

  1. Verify package exists:

    # npm
    npm view [package-name]
    
    # PyPI
    pip index versions [package-name]
    

  2. Check package age and downloads:

  3. Very new packages with few downloads warrant extra scrutiny
  4. Established packages are more likely legitimate

  5. Verify against official documentation:

  6. Does the framework/library's official docs recommend this package?
  7. Is it in the ecosystem's recommended tooling?

  8. Check for typosquatting:

  9. Does the name closely resemble a popular package?
  10. Is the publisher expected for this package?

  11. Review AI's reasoning:

  12. Why did the AI suggest this specific package?
  13. Are there better-known alternatives?

Red Flags for AI-Suggested Packages:

Signal Concern
Package doesn't exist AI hallucination (slopsquatting target)
Very few downloads May be squatted or malicious
Created very recently Could be registered to exploit AI suggestions
Name very similar to popular package Potential typosquatting
No clear source repository Difficult to evaluate

Verification Workflow:

AI suggests: import awesome_utils

1. Does awesome_utils exist on PyPI?
   - No → Don't use (hallucination)
   - Yes → Continue

2. When was it created?
   - Very recent → Extra scrutiny
   - Established → Continue

3. How many downloads?
   - Very few → Investigate further
   - Reasonable → Continue

4. Who maintains it?
   - Unknown → Research maintainer
   - Reputable → Continue

5. Standard vetting process
   - Security, maintenance, functionality, licensing

Code reviews increasingly catch AI-hallucinated package names—dependencies that either don't exist or were maliciously registered after AI models began suggesting them.1 Developers often assume AI-recommended packages are legitimate without verification, creating a new attack vector.

Recommendations

For Developers:

  1. Pause before install. Take five minutes to evaluate a dependency before adding it. The time investment pays off in avoided problems.

  2. Verify AI suggestions. Never install an AI-suggested package without confirming it exists, has reasonable adoption, and meets your criteria.

  3. Document decisions. Record why you chose a dependency. Future you (or teammates) will appreciate the context.

  4. Consider alternatives. Always evaluate at least one alternative, including "no dependency."

For Engineering Managers:

  1. Establish vetting process. Define your organization's dependency evaluation requirements based on risk tier.

  2. Provide tooling. Give developers easy access to tools that check security, maintenance, and licensing.

  3. Create decision templates. Make it easy to document dependency decisions consistently.

  4. Review dependency additions. Include dependency review in code review process, especially for critical-tier additions.

For Organizations:

  1. Define approved/blocked lists. Pre-approve common dependencies; block known-problematic ones.

  2. Automate where possible. Use policy engines to automatically evaluate against criteria.

  3. Track dependency decisions. Maintain record of what was evaluated and why decisions were made.

  4. Update criteria regularly. As threats evolve (e.g., AI hallucination attacks), update vetting processes.

Dependency selection is too important to leave to chance or convenience. Organizations that invest in systematic vetting processes make better decisions, avoid problems, and build more secure, maintainable software. The few minutes spent evaluating a dependency before adoption save hours of remediation later.


  1. Lanyado, Bar and Nadler, Amit. "Sleepy Package Attack: AI Coding Assistants Hallucininate Non-existent Packages," Lasso Security, March 2023, https://www.lasso.security/blog/ai-package-hallucinations