Dependency Security: Scanning and Management

Reverend Philip Nov 30, 2025 9 min read

Keep your dependencies secure. Learn about vulnerability scanning tools, update strategies, and supply chain security practices.

Modern applications rely on hundreds of dependencies, each a potential entry point for attackers. Supply chain attacks are increasingly common, making dependency security scanning essential for any serious development team. This guide covers tools, strategies, and best practices for keeping your dependencies secure.

The Supply Chain Risk

Why Dependencies Are Risky

Your application's security is only as strong as its weakest dependency. Consider:

  • Direct dependencies: Packages you explicitly install
  • Transitive dependencies: Dependencies of your dependencies
  • Scale: A typical Laravel project has 100+ packages; a Node project can have 1000+

Real-World Attacks

These aren't theoretical risks. High-profile supply chain attacks happen regularly and affect thousands of applications:

  • event-stream (2018): Malicious code added to steal cryptocurrency
  • ua-parser-js (2021): Compromised to mine cryptocurrency and steal passwords
  • colors/faker (2022): Maintainer sabotaged own packages
  • Log4Shell (2021): Critical vulnerability in ubiquitous logging library

Each of these incidents impacted countless production systems. Proactive scanning is your best defense against becoming the next victim.

Vulnerability Scanning Tools

Composer (PHP)

Composer's built-in audit command checks your installed packages against known vulnerability databases. Run it regularly and integrate it into your CI pipeline.

# Built-in audit command (Composer 2.4+)
composer audit

# Output
Found 2 security vulnerability advisories affecting 2 packages.

symfony/http-kernel (v6.0.0)
  - CVE-2022-24894: Cookie header not properly validated

laravel/framework (v9.0.0)
  - GHSA-3p32-j457-pg5x: SQL injection vulnerability

The output includes CVE identifiers you can research for severity and impact details.

npm (Node.js)

npm's audit command is similar to Composer's but can also attempt automatic fixes for some vulnerabilities by updating to patched versions.

# Built-in audit
npm audit

# Fix automatically where possible
npm audit fix

# Generate JSON report
npm audit --json > audit-report.json

Be cautious with npm audit fix - it may update to major versions that introduce breaking changes. Review changes before deploying.

Other Package Managers

Most modern package managers include security auditing. Here's how to run scans across different ecosystems. You can use these commands regardless of which language your project uses:

# Python pip
pip-audit

# Ruby bundler
bundle audit check --update

# Go
govulncheck ./...

# Rust
cargo audit

Pick the command that matches your project's package manager and run it regularly. Each tool queries vulnerability databases specific to its ecosystem.

Automated Scanning Services

GitHub Dependabot

Enable in repository settings or with config file:

Dependabot configuration lets you control which ecosystems to scan, how often, and how to label the resulting pull requests.

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "composer"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    labels:
      - "dependencies"
      - "php"

  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    labels:
      - "dependencies"
      - "javascript"

Dependabot will:

  • Check for known vulnerabilities
  • Create PRs to update vulnerable packages
  • Group updates intelligently

The open-pull-requests-limit prevents Dependabot from overwhelming your repository with too many PRs at once.

Snyk

More comprehensive scanning with deeper analysis:

Snyk goes beyond basic vulnerability matching to analyze how vulnerabilities might be exploited in your specific codebase. It can identify if vulnerable code paths are actually reachable.

# Install
npm install -g snyk

# Authenticate
snyk auth

# Test for vulnerabilities
snyk test

# Monitor project (continuous scanning)
snyk monitor

The snyk monitor command registers your project for continuous monitoring - you'll get alerts when new vulnerabilities are discovered that affect your dependencies.

CI Integration:

Integrating Snyk into CI ensures every pull request is scanned before merge. Failed scans can block deployment of vulnerable code.

# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]

jobs:
  snyk:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: snyk/actions/php@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

OWASP Dependency-Check

Open source, supports many ecosystems:

OWASP Dependency-Check is free and can scan projects regardless of language. The --failOnCVSS flag lets you set a threshold - fail the build only for vulnerabilities above a certain severity.

# Run scan
dependency-check --project "MyApp" --scan /path/to/project

# CI integration
dependency-check --project "MyApp" --scan . --format JSON --failOnCVSS 7

CVSS 7 is typically considered "high severity" - you might choose to fail on 9+ for critical only, or 4+ if you want stricter enforcement.

CI/CD Integration

GitHub Actions

This workflow runs security audits on every push and pull request, plus a daily scheduled scan to catch newly disclosed vulnerabilities. The artifact upload preserves the audit report for investigation when scans fail.

name: Security
on:
  push:
    branches: [main]
  pull_request:
  schedule:
    - cron: '0 0 * * *'  # Daily scan

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'

      - name: Install dependencies
        run: composer install

      - name: Run security audit
        run: composer audit --format=json > audit.json

      - name: Check for vulnerabilities
        run: |
          if [ -s audit.json ]; then
            cat audit.json
            exit 1
          fi

      - name: Upload audit report
        uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: security-audit
          path: audit.json

The scheduled scan (cron: '0 0 * * *') runs at midnight UTC daily, catching vulnerabilities disclosed after your last code change.

GitLab CI

GitLab has built-in support for dependency scanning reports. The artifact format integrates with GitLab's security dashboard for tracking vulnerabilities across projects.

security-audit:
  stage: test
  script:
    - composer audit --format=json > gl-dependency-scanning-report.json
    - npm audit --json > npm-audit.json
  artifacts:
    reports:
      dependency_scanning: gl-dependency-scanning-report.json

Update Strategies

Semantic Versioning Awareness

Understanding version constraints helps you balance stability and security. The caret (^) allows minor updates which typically include security fixes, while exact pinning gives you control at the cost of manual updates.

// composer.json
{
    "require": {
        "laravel/framework": "^11.0",    // Accept minor/patch updates
        "vendor/risky": "10.2.3"         // Pin to exact version
    }
}

Regular Update Schedule

Establish a routine for checking and applying updates. Don't let dependencies drift for months - the longer you wait, the harder updates become.

# Weekly routine
composer outdated --direct  # Check for updates
composer update --dry-run   # Preview changes
composer update             # Apply updates
php artisan test            # Verify nothing broke

The --direct flag shows only your direct dependencies, filtering out the noise of transitive dependency updates.

Automated Update PRs

Configure Dependabot or Renovate to:

  • Create PRs for updates
  • Run CI tests automatically
  • Allow auto-merge for patch updates

Renovate offers fine-grained control over auto-merging. You might auto-merge patch updates for well-tested packages while requiring review for major updates.

# renovate.json
{
  "extends": ["config:base"],
  "packageRules": [
    {
      "matchUpdateTypes": ["patch"],
      "automerge": true
    }
  ],
  "vulnerabilityAlerts": {
    "enabled": true,
    "labels": ["security"]
  }
}

Security vulnerability PRs get labeled distinctly so they're easy to prioritize in your review queue.

Lock File Best Practices

Always Commit Lock Files

Lock files are essential for reproducible builds. Without them, different developers and environments might get different dependency versions. Make sure you're tracking these files in version control:

# PHP
git add composer.lock

# Node.js
git add package-lock.json
# or
git add yarn.lock

# Python
git add requirements.txt  # or Pipfile.lock

You might be tempted to ignore lock files to reduce merge conflicts, but the security and reproducibility benefits far outweigh the inconvenience. Lock files ensure:

  • Reproducible builds across environments
  • Same versions in dev, staging, production
  • Visibility into transitive dependencies

Review Lock File Changes

When updating, review what actually changes:

Lock file diffs show exactly which versions changed, including transitive dependencies. This visibility helps you understand the full impact of updates.

# Show packages that will change
composer update --dry-run

# After update, review diff
git diff composer.lock

Large unexpected changes in the lock file warrant investigation - they might indicate version constraint issues or dependency conflicts.

Handling Vulnerabilities

Triage Process

  1. Assess severity: CVSS score, exploitability
  2. Check exposure: Is the vulnerable code path used?
  3. Find fix: Updated version, patch, workaround
  4. Test thoroughly: Especially for major version bumps
  5. Deploy quickly: Critical vulnerabilities need immediate attention

When Updates Aren't Available

Sometimes the maintainer hasn't released a fix yet, or updating would require major breaking changes. Here are your options.

// Option 1: Fork and patch
// composer.json
{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/your-org/forked-package"
        }
    ]
}

// Option 2: Inline patching
// composer.json with cweagans/composer-patches
{
    "extra": {
        "patches": {
            "vendor/package": {
                "Security fix": "patches/security-fix.patch"
            }
        }
    }
}

Forking gives you full control but creates maintenance burden. The composer-patches approach is lighter but can break with package updates.

Temporary Mitigations

If you can't update immediately:

  • Add input validation before vulnerable code
  • Disable affected feature
  • Add WAF rules to block exploitation
  • Monitor for exploitation attempts

Software Bill of Materials (SBOM)

Generate an SBOM for compliance and incident response:

An SBOM is a complete inventory of your software components. When a new vulnerability is announced, you can quickly check if you're affected without manually auditing every project.

# Using Syft
syft packages dir:. -o spdx-json > sbom.json

# Using CycloneDX
composer require --dev cyclonedx/cyclonedx-php-composer
composer make-bom

SBOM helps you:

  • Know what's in your software
  • Respond quickly to new vulnerabilities
  • Meet compliance requirements

Many enterprises now require SBOMs from vendors - generating them proactively positions you well for these requests.

Metrics and Monitoring

Track dependency health over time:

These metrics help you measure progress and identify projects that need attention. A dashboard showing vulnerability trends across all your repositories provides valuable oversight.

# Dashboard metrics
- Total dependencies
- Dependencies with known vulnerabilities
- Average age of dependencies
- Time to remediate vulnerabilities

Alerting

Don't wait until your next scheduled review to learn about critical vulnerabilities. Set up alerts for:

  • New critical vulnerabilities in your dependencies
  • Dependencies that haven't been updated in 1+ year
  • Deprecated packages you're still using

Many of the tools mentioned earlier (Snyk, Dependabot, GitHub Security Advisories) can send notifications when new vulnerabilities are discovered.

Best Practices Summary

  1. Scan continuously: Daily automated scans, not just at deploy time
  2. Update regularly: Don't let technical debt accumulate
  3. Pin responsibly: Use ranges for trusted packages, pin risky ones
  4. Review carefully: Especially for packages with broad access
  5. Minimize dependencies: Fewer dependencies = smaller attack surface
  6. Use trusted sources: Official registries, verified publishers
  7. Monitor for typosquatting: Watch for malicious lookalike packages
  8. Keep lock files updated: Review and commit all changes
  9. Have a response plan: Know how you'll handle critical vulnerabilities
  10. Document decisions: Why you kept that old version, accepted that risk

Conclusion

Dependency security isn't a one-time task;it's an ongoing process. Automate scanning in CI/CD, establish regular update routines, and have a clear process for responding to vulnerabilities. The effort invested in maintaining secure dependencies pays off in reduced incident response and better sleep at night.

Share this article

Related Articles

Feature Flags Best Practices

Control feature rollouts with flags. Learn flag types, targeting rules, technical debt management, and operational excellence.

Jan 8, 2026

Zero-Downtime Database Migrations

Migrate database schemas without service interruption. Learn expand-contract patterns, backward compatibility, and rollback strategies.

Jan 5, 2026

Need help with your project?

Let's discuss how we can help you build reliable software.