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-paddoesn'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:
- Could I write this in < 50 lines of code?
- Is the functionality truly complex enough to warrant external code?
- 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:
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:
- Registry search: npm search, PyPI search for similar packages
- Awesome lists: Curated lists (e.g., awesome-python, awesome-node)
- Stack Overflow: See what others use for similar problems
- deps.dev: Related packages and dependency information
- npm-compare: Side-by-side comparison (for npm)
- 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:
-
Verify package exists:
-
Check package age and downloads:
- Very new packages with few downloads warrant extra scrutiny
-
Established packages are more likely legitimate
-
Verify against official documentation:
- Does the framework/library's official docs recommend this package?
-
Is it in the ecosystem's recommended tooling?
-
Check for typosquatting:
- Does the name closely resemble a popular package?
-
Is the publisher expected for this package?
-
Review AI's reasoning:
- Why did the AI suggest this specific package?
- 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:
-
Pause before
install. Take five minutes to evaluate a dependency before adding it. The time investment pays off in avoided problems. -
Verify AI suggestions. Never install an AI-suggested package without confirming it exists, has reasonable adoption, and meets your criteria.
-
Document decisions. Record why you chose a dependency. Future you (or teammates) will appreciate the context.
-
Consider alternatives. Always evaluate at least one alternative, including "no dependency."
For Engineering Managers:
-
Establish vetting process. Define your organization's dependency evaluation requirements based on risk tier.
-
Provide tooling. Give developers easy access to tools that check security, maintenance, and licensing.
-
Create decision templates. Make it easy to document dependency decisions consistently.
-
Review dependency additions. Include dependency review in code review process, especially for critical-tier additions.
For Organizations:
-
Define approved/blocked lists. Pre-approve common dependencies; block known-problematic ones.
-
Automate where possible. Use policy engines to automatically evaluate against criteria.
-
Track dependency decisions. Maintain record of what was evaluated and why decisions were made.
-
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.
-
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 ↩