Skip to content

ponomarenko/verdaccio-security-filter

Repository files navigation

Verdaccio Security Filter Plugin

Advanced security filter plugin for Verdaccio with dual-layer protection architecture combining middleware interception and metadata filtering for comprehensive package security.

Stand With Ukraine npm version npm downloads CI Tests TypeScript Node Verdaccio

🏗️ Dual-Layer Architecture

This plugin implements two independent security layers for complete protection:

Layer 1: Middleware (Always Active)

  • Whitelist/Blacklist filtering - Control allowed packages
  • Pattern-based blocking - Block by regex patterns
  • Scope control - Filter by npm scopes
  • Tarball interception - Block downloads even if metadata cached
  • Version blocking - Block specific versions/ranges

Layer 2: Filter Metadata (Deep Inspection)

  • CVE vulnerability scanning - OSV API integration
  • License compliance - SPDX validation
  • Package age verification - Block newly created packages
  • Full metadata access - Deep package inspection

Why two layers? Middleware catches everything at HTTP level, while filter_metadata provides deep inspection when metadata is available. See DUAL-LAYER-ARCHITECTURE.md for details.

🚀 Features

✅ Implemented Features

🔒 Version Management

  • Version Range Blocking - Block vulnerable versions using semver ranges
    • Block Strategy: Completely remove versions from registry
    • Fallback Strategy: Transparently redirect to safe versions
  • Exact Version Blocking - Block specific package@version combinations
  • Semver Support - Full semver syntax (^, ~, >, >=, <, <=, x, *)

🛡️ CVE & Vulnerability Scanning

  • OSV Database Integration - Automatic vulnerability scanning via OSV API
  • Severity Filtering - Filter by severity: low, medium, high, critical
  • Auto-Block Vulnerable Packages - Automatically block packages with known CVEs
  • Caching System - Configurable cache with update intervals
  • Multiple Database Support - Ready for OSV, Snyk, GitHub Advisory

⚖️ License Compliance

  • License Filtering - Enforce license policies with allowed/blocked lists
  • SPDX Expression Support - Parse complex license expressions (OR/AND operators)
  • Require License - Option to block packages without license information
  • Pre-defined Lists - Common open-source and copyleft license collections

🔐 Access Control

  • Whitelist Mode - Only explicitly approved packages allowed
  • Pattern-based Whitelisting - Regex patterns for package approval
  • Version Constraints - Lock approved packages to specific version ranges
  • Scope Control - Whitelist/blacklist package scopes (@scope/package)

📊 Monitoring & Observability

  • Enhanced Logging - Configurable log levels (debug, info, warn, error)
  • Metrics Collection - Track security events (blocks, fallbacks, CVEs, license violations)
  • Security Audit Trail - Detailed logging of all security decisions
  • Customizable Output - Log to stdout or file in JSON format

🔍 Additional Security

  • Pattern-based Blocking - Block suspicious packages by name patterns (regex)
  • Package Age Filtering - Block packages or versions that are too new (protect against newly published malicious packages)
    • Minimum Package Age - Require packages to exist for a minimum number of days
    • Minimum Version Age - Require specific versions to exist for a minimum number of days
    • Warn-Only Mode - Log warnings without blocking
  • Author Filtering - Block packages based on author information
    • Block by Author Name - Block specific author names or patterns
    • Block by Email - Block specific email addresses or patterns
    • Block by Email Domain - Block entire email domains (e.g., .ru, yandex.ru)
    • Block by Region - Block authors from specific regions based on email domains
    • Maintainer & Contributor Checking - Validates all package maintainers and contributors
    • Warn-Only Mode - Log warnings without blocking
  • Middleware Interception - HTTP middleware that blocks tarball downloads for blocked packages
    • Prevents blocked packages from being installed as dependencies
    • Intercepts requests to /:package/-/:filename.tgz routes
    • Returns 403 Forbidden with detailed error messages
  • Size Limits - Enforce minimum and maximum package sizes
  • Metadata Validation - Verify package integrity and detect dangerous characters
  • Checksum Enforcement - Ensure package integrity

⚙️ Reliability & Error Handling

  • Fail-Safe/Fail-Closed Configuration - Choose error handling strategy
    • Fail-Open (Default) - Allow packages on errors (availability priority)
    • Fail-Closed - Block packages on errors (security priority)
    • Granular Control - Different strategies for filter, CVE, and license checks
  • Retry Logic - Automatic retry with exponential backoff for API calls
    • 3 retries with increasing delays (1s, 2s, 4s)
    • Rate limiting detection and handling
    • Request timeout protection (10s)
  • Resilient CVE Scanning - Production-ready vulnerability checking
    • Network failure recovery
    • API timeout protection
    • Graceful degradation on errors

🔮 Planned Features (Roadmap)

Phase 3: Advanced Security

  • Dependency Depth Limiting - Limit dependency tree depth and total count
  • Circular Dependency Detection - Block packages with circular dependencies
  • Rate Limiting - Detect and block suspicious download patterns
  • Typosquatting Detection - AI-powered detection of similar package names
  • Package Signing Verification - PGP signature validation
  • Custom Validation Scripts - Execute custom security checks

Phase 4: Enterprise Features

  • Integration with Security Scanners - npm audit, Snyk API, Sonatype
  • Webhook Notifications - Real-time alerts for security events
  • Web Dashboard - Visual interface for security analytics
  • Email/Slack Notifications - Alert channels for critical events
  • Audit Reports - Generate compliance reports (PDF, CSV, JSON)
  • Multi-Registry Support - Fallback to other registries
  • ML-based Anomaly Detection - Machine learning for threat detection

Phase 5: Developer Experience

  • Dry Run Mode - Test rules without actually blocking
  • Auto-approve Criteria - Automatic approval based on npm stats (downloads, stars)
  • CLI Tool - Command-line interface for rule management
  • Visual Studio Code Extension - IDE integration
  • GitHub Action - CI/CD integration

📦 Installation

Prerequisites

  • Node.js >= 22.0.0
  • Verdaccio >= 5.0.0
npm install -g verdaccio

Install Plugin

# Install from npm (when published)
npm install -g verdaccio-security-filter

# Or install locally for development
git clone https://github.com/ponomarenko/verdaccio-security-filter.git
cd verdaccio-security-filter
npm install
npm run build
npm link

🔧 How It Works

This plugin implements two layers of protection to block malicious packages:

Layer 1: Metadata Filtering (filter_metadata)

When a client requests package information (e.g., npm info lodash), the plugin:

  1. Checks if the package is allowed (whitelist mode)
  2. Validates against blocked patterns, scopes, and age requirements
  3. Throws HTTP 404 error for completely blocked packages (patterns, scopes, whitelist violations)
  4. Filters out specific blocked versions from the versions list for partial blocks

Result: Blocked packages return "404 Not Found" - as if they don't exist in the registry.

Layer 2: Middleware Interception (register_middlewares)

When a client tries to download a tarball file (e.g., during npm install), the plugin:

  1. Intercepts all HTTP requests early in the middleware chain
  2. Extracts package name and version from the request URL
  3. Applies all security checks (whitelist, patterns, scopes, blocked versions, range rules)
  4. Returns 403 Forbidden for blocked packages with detailed error message

Result: Even if metadata is cached, tarball downloads are blocked at the HTTP level.

Why Both Layers?

  • Metadata filtering (404) - Makes blocked packages invisible to npm/yarn
  • Middleware interception (403) - Blocks tarball downloads even with cached metadata
  • Together, they provide complete protection against blocked packages being installed in any way

Example flow when a blocked package is requested:

npm install hawk
→ GET /hawk (metadata request)
→ [Security Filter] Blocked hawk@* - Package is not in whitelist
→ HTTP 404 Not Found: Package blocked by security filter: Not in whitelist
→ npm ERR! 404 Not Found - GET http://localhost:4873/hawk

npm install (with hawk as dependency)
→ GET /hawk/-/hawk-9.0.1.tgz (tarball request)
→ [Middleware] Tarball request: hawk/hawk-9.0.1.tgz
→ [Security Filter] Blocked [email protected] - Package is not in whitelist
→ HTTP 403 Forbidden: {"error": "Package blocked by security filter", "reason": "Package is not in whitelist"}

⚙️ Configuration

Quick Start (Middleware Only)

Minimal configuration using only Layer 1 (Middleware):

middlewares:
  security-filter:
    enabled: true
    mode: whitelist
    whitelist:
      packages:
        - lodash
        - express
      patterns:
        - "^@types/.*"

Full Protection (Dual-Layer)

Recommended: Use both layers for maximum security:

# Enable filter_metadata (Layer 2)
packages:
  '@*/*':
    access: $all
    publish: $authenticated
    proxy: npmjs
    storage: security-filter  # Enable Layer 2!

  '**':
    access: $all
    publish: $authenticated
    proxy: npmjs
    storage: security-filter  # Enable Layer 2!

# Configure security filter
middlewares:
  security-filter:
    enabled: true

    # Layer 1: Basic filtering (Middleware)
    mode: whitelist
    whitelist:
      packages: [lodash, express]
      patterns: ["^@types/.*"]

    blockedVersions:
      - "[email protected]"

    # Layer 2: Deep inspection (filter_metadata)
    cveCheck:
      enabled: true
      autoBlock: true
      severity: [critical, high]

    licenses:
      allowed: [MIT, Apache-2.0, BSD-3-Clause]

    packageAge:
      enabled: true
      minPackageAgeDays: 7

Advanced Configuration with CVE Scanning

# Layer 1: Metadata filtering
filters:
  security-filter:
    enabled: true

    # CVE vulnerability scanning
    cveCheck:
      enabled: true
      databases:
        - osv
        - github
      severity:
        - high
        - critical
      autoBlock: true
      updateInterval: 24          # hours
      cacheDir: ./.security-cache

    # License compliance
    licenses:
      allowed:
        - MIT
        - Apache-2.0
        - BSD-3-Clause
      blocked:
        - GPL-3.0
        - AGPL-3.0
      requireLicense: true

    # Package age filtering
    packageAge:
      enabled: true
      minPackageAgeDays: 7       # Packages must be at least 7 days old
      minVersionAgeDays: 3       # Versions must be at least 3 days old
      warnOnly: false            # Block instead of just warning

    # Version range rules
    versionRangeRules:
      - package: lodash
        range: "<4.17.21"
        strategy: fallback
        fallbackVersion: "4.17.21"
        reason: "CVE-2021-23337: Command injection"

      - package: minimist
        range: "<1.2.6"
        strategy: block
        reason: "CVE-2021-44906: Prototype pollution"

# Layer 2: Middleware interception
middlewares:
  security-filter:
    enabled: true

Enterprise Whitelist Mode

# Layer 1: Metadata filtering
filters:
  security-filter:
    enabled: true

    # Only approved packages allowed
    mode: whitelist

    whitelist:
      packages:
        - lodash
        - express
        - react
      patterns:
        - "^@mycompany/.*"
        - "^@types/.*"
      versions:
        lodash: "^4.17.21"
        express: "^4.18.0"

    # Enhanced logging
    logger:
      level: info
      enabled: true
      includeTimestamp: true

    # Metrics for analytics
    metrics:
      enabled: true
      output: file
      filePath: ./security-metrics.json

# Layer 2: Middleware interception
middlewares:
  security-filter:
    enabled: true

High Security Configuration

# Layer 1: Metadata filtering
filters:
  security-filter:
    enabled: true
    mode: whitelist

    whitelist:
      packages:
        - lodash
        - axios
      versions:
        lodash: "4.17.21"    # Lock to exact version
        axios: "1.6.0"

    cveCheck:
      enabled: true
      databases: [osv, github, snyk]
      severity: [low, medium, high, critical]  # Block ALL
      autoBlock: true
      updateInterval: 6                         # Check every 6 hours

    licenses:
      allowed: [MIT, Apache-2.0, BSD-3-Clause]
      blocked: [GPL-3.0, AGPL-3.0, LGPL-3.0]
      requireLicense: true

    minPackageSize: 10000      # 10KB minimum
    maxPackageSize: 10485760   # 10MB maximum

    logger:
      level: debug             # Log everything
      enabled: true
      includeTimestamp: true

    metrics:
      enabled: true
      output: file
      filePath: /var/log/verdaccio/security-metrics.jsonl

# Layer 2: Middleware interception
middlewares:
  security-filter:
    enabled: true

📚 Configuration Reference

Main Options

Option Type Default Description
mode string blacklist Filter mode: blacklist or whitelist
blockedVersions string[] [] List of package@version to block
blockedPatterns string[] [] Regex patterns for package names
allowedScopes string[] [] Allowed package scopes
blockedScopes string[] [] Blocked package scopes
minPackageSize number 0 Minimum package size in bytes
maxPackageSize number 104857600 Maximum package size (100MB)
enforceChecksum boolean true Enforce checksum validation

CVE Check Options

Option Type Default Description
cveCheck.enabled boolean false Enable CVE scanning
cveCheck.databases string[] ['osv'] Databases: osv, snyk, github
cveCheck.severity string[] ['high', 'critical'] Severity levels to check
cveCheck.autoBlock boolean false Auto-block vulnerable packages
cveCheck.updateInterval number 24 Cache update interval (hours)
cveCheck.cacheDir string ./.security-cache Cache directory path

License Options

Option Type Default Description
licenses.allowed string[] [] Allowed license list
licenses.blocked string[] [] Blocked license list
licenses.requireLicense boolean false Require license field

Whitelist Options

Option Type Default Description
whitelist.packages string[] [] Approved package names
whitelist.patterns string[] [] Regex patterns for approval
whitelist.versions object {} Version constraints per package

Logger Options

Option Type Default Description
logger.level string info Log level: debug, info, warn, error
logger.enabled boolean true Enable logging
logger.includeTimestamp boolean false Include timestamps in logs

Metrics Options

Option Type Default Description
metrics.enabled boolean false Enable metrics collection
metrics.output string stdout Output: stdout or file
metrics.filePath string ./security-metrics.json Metrics file path

Package Age Options

Option Type Default Description
packageAge.enabled boolean false Enable package age filtering
packageAge.minPackageAgeDays number 0 Minimum age for packages (days)
packageAge.minVersionAgeDays number undefined Minimum age for versions (days)
packageAge.warnOnly boolean false Only warn, don't block

Author Filter Options

Option Type Default Description
authorFilter.enabled boolean false Enable author filtering
authorFilter.blockedAuthors string[] [] List of author names to block
authorFilter.blockedAuthorPatterns string[] [] Regex patterns for author names
authorFilter.blockedEmails string[] [] List of email addresses to block
authorFilter.blockedEmailPatterns string[] [] Regex patterns for author emails
authorFilter.blockedEmailDomains string[] [] Email domains to block (e.g., .ru, yandex.ru)
authorFilter.blockedRegions string[] [] Region codes to block (ru, cn, by, kp, ir, sy, cu, sd)
authorFilter.requireVerifiedEmail boolean false Require author email information
authorFilter.warnOnly boolean false Only warn, don't block

Error Handling Options

Option Type Default Description
errorHandling.onFilterError 'fail-open' | 'fail-closed' 'fail-open' Strategy when filter errors occur
errorHandling.onCveCheckError 'fail-open' | 'fail-closed' 'fail-open' Strategy when CVE check fails
errorHandling.onLicenseCheckError 'fail-open' | 'fail-closed' 'fail-open' Strategy when license check fails

Error Handling Strategies:

  • fail-open (Default): Allow packages through on errors (prioritizes availability)
  • fail-closed: Block packages on errors (prioritizes security)

Example Configuration:

# Production: Security-first approach
errorHandling:
  onFilterError: fail-closed
  onCveCheckError: fail-closed
  onLicenseCheckError: fail-closed

# Development: Availability-first approach
errorHandling:
  onFilterError: fail-open
  onCveCheckError: fail-open
  onLicenseCheckError: fail-open

# Balanced: Block only on license failures
errorHandling:
  onFilterError: fail-open
  onCveCheckError: fail-open
  onLicenseCheckError: fail-closed

Version Range Rules

{
  package: string;           // Package name
  range: string;             // Semver range
  strategy: 'block' | 'fallback';
  fallbackVersion?: string;  // Required for fallback strategy
  reason?: string;           // Explanation for blocking
}

📖 Examples

See the examples directory for complete configuration examples:

🧪 Testing

# Run all tests
npm test

# Run tests with coverage
npm test:coverage

# Run tests in watch mode
npm test:watch

Test Results:

  • ✅ 108 tests passing
  • ✅ 60%+ code coverage
  • ✅ SecurityFilterPlugin: 21 tests
  • ✅ PackageAgeChecker: 13 tests
  • ✅ SecurityLogger: 16 tests
  • ✅ LicenseChecker: 15 tests
  • ✅ WhitelistChecker: 15 tests
  • ✅ AuthorChecker: 28 tests

🔧 Development

# Install dependencies
npm install

# Build
npm run build

# Lint
npm run lint

# Watch mode for development
npm run build -- --watch

📊 Metrics & Monitoring

When metrics are enabled, the plugin tracks:

  • block - Packages blocked by version/pattern/scope rules
  • fallback - Versions redirected to safe alternatives
  • publish_rejected - Publish attempts rejected
  • cve_detected - CVE vulnerabilities found
  • license_blocked - Packages blocked by license rules
  • package_too_new - Packages/versions blocked due to age restrictions
  • author_blocked - Packages blocked due to author/region filtering

Example metrics output:

{
  "timestamp": "2025-01-15T10:30:00.000Z",
  "event": "cve_detected",
  "packageName": "lodash",
  "version": "4.17.20",
  "reason": "CVE-2021-23337 (high)",
  "metadata": {
    "cveId": "CVE-2021-23337",
    "severity": "high"
  }
}

🛠️ Use Cases

1. Block Known Vulnerabilities

versionRangeRules:
  - package: lodash
    range: ">=4.17.0 <4.17.21"
    strategy: block
    reason: "CVE-2021-23337: Command injection vulnerability"

2. Transparent Security Patches (Fallback)

versionRangeRules:
  - package: axios
    range: "0.21.1"
    strategy: fallback
    fallbackVersion: "0.21.4"
    reason: "SSRF vulnerability fix"

3. Enforce Corporate License Policy

licenses:
  allowed:
    - MIT
    - Apache-2.0
    - BSD-3-Clause
  blocked:
    - GPL-3.0
    - AGPL-3.0
  requireLicense: true

4. Whitelist Only Approved Packages

mode: whitelist
whitelist:
  packages:
    - lodash
    - express
  patterns:
    - "^@mycompany/.*"
  versions:
    lodash: "^4.17.21"

5. Automatic CVE Scanning

cveCheck:
  enabled: true
  databases: [osv, github]
  severity: [high, critical]
  autoBlock: true
  updateInterval: 12

6. Block Recently Published Packages

# Protect against newly published malicious packages
packageAge:
  enabled: true
  minPackageAgeDays: 7       # Package must exist for 7 days
  minVersionAgeDays: 3       # Version must exist for 3 days
  warnOnly: false            # Block, don't just warn

7. Block Packages by Author/Region

# Block packages from specific authors, emails, or regions
authorFilter:
  enabled: true
  # Block specific author names
  blockedAuthors:
    - "Suspicious Author"
    - "Known Bad Actor"
  # Block author names matching patterns
  blockedAuthorPatterns:
    - "^Bot.*"
    - ".*Spammer$"
  # Block specific email addresses
  blockedEmails:
    - "[email protected]"
  # Block email patterns
  blockedEmailPatterns:
    - ".*@temporary-mail\\.com$"
  # Block entire email domains
  blockedEmailDomains:
    - ".ru"           # All .ru domains
    - "yandex.ru"     # Specific domain
    - "mail.ru"
  # Block by region (includes multiple common domains)
  blockedRegions:
    - "ru"            # Russia (.ru, yandex.ru, mail.ru, etc.)
    - "cn"            # China (.cn, qq.com, 163.com, etc.)
    - "by"            # Belarus
    - "kp"            # North Korea
  # Require author information
  requireVerifiedEmail: true
  # Warn-only mode (don't block, just log)
  warnOnly: false

🔐 Security Best Practices

  1. Enable CVE Scanning - Automatically detect and block vulnerable packages
  2. Use Whitelist Mode - For maximum security in sensitive environments
  3. Enforce License Compliance - Prevent legal issues with license filtering
  4. Enable Package Age Filtering - Block newly published packages to prevent supply chain attacks
  5. Enable Author Filtering - Block packages from untrusted authors or regions
  6. Enable Metrics - Track security events for audit and compliance
  7. Regular Updates - Keep the plugin and CVE database cache updated
  8. Test Rules - Use dry run mode (planned) before applying strict rules
  9. Monitor Logs - Review security logs regularly for suspicious activity

🐛 Troubleshooting

Plugin not loading

  • Verify Verdaccio version >= 5.0.0
  • Check plugin is listed in config.yaml under filters
  • Ensure plugin is installed globally or linked correctly

CVE scanning not working

Tests failing

  • Ensure Node.js >= 22.0.0
  • Run npm install to update dependencies
  • Clear Jest cache: npx jest --clearCache

Package blocked unexpectedly

  • Check logs for the reason: logger.level: debug
  • Review all active rules (patterns, scopes, CVE, license)
  • In whitelist mode, ensure package is explicitly approved

📄 License

MIT © Vitaliy Ponomarenko

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Run tests (npm test)
  4. Commit your changes (git commit -m 'Add amazing feature')
  5. Push to the branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

📞 Support

🙏 Acknowledgments

  • Verdaccio - The awesome private npm registry
  • OSV - Open Source Vulnerabilities database
  • All contributors and users of this plugin

Made with ❤️ for the npm security community

About

Advanced security filter plugin for Verdaccio with version range blocking and fallback strategies

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •