Express.js Deprecated Request Library Usage

Medium Risk Deprecated Software
expressdeprecated-libraryrequestjavascriptmaintenancehttp-client

What it is

The Express.js application uses the deprecated 'request' library for HTTP requests, which is no longer maintained and may contain security vulnerabilities. The request library has been deprecated since 2020 and should be replaced with more secure and actively maintained alternatives.

// Vulnerable: Using deprecated 'request' library
const request = require('request');

app.get('/api/external', (req, res) => {
  const url = 'https://api.example.com/data';
  
  request(url, (error, response, body) => {
    if (error) {
      return res.status(500).json({ error: 'Request failed' });
    }
    res.json(JSON.parse(body));
  });
});
// Secure: Using modern 'axios' library
const axios = require('axios');

app.get('/api/external', async (req, res) => {
  const url = 'https://api.example.com/data';
  
  try {
    const response = await axios.get(url, {
      timeout: 5000,
      maxRedirects: 5,
      validateStatus: (status) => status < 400
    });
    
    res.json(response.data);
  } catch (error) {
    console.error('API request failed:', error.message);
    res.status(500).json({ error: 'External API request failed' });
  }
});

💡 Why This Fix Works

The vulnerable code was updated to address the security issue.

Why it happens

Express applications continue using the deprecated 'request' library despite it being officially deprecated in February 2020 and receiving no security updates since then. Organizations fail to track dependency lifecycles or monitor deprecation notices from maintainers. Applications deployed years ago remain in production without dependency reviews or updates. Teams prioritize feature development over maintenance work, postponing library migrations indefinitely. package-lock.json locks in old request version preventing even accidental updates. No regular schedule for reviewing and updating dependencies means vulnerable, unmaintained packages accumulate technical debt and security risk over time.

Root causes

Using Outdated Dependencies Without Regular Updates

Express applications continue using the deprecated 'request' library despite it being officially deprecated in February 2020 and receiving no security updates since then. Organizations fail to track dependency lifecycles or monitor deprecation notices from maintainers. Applications deployed years ago remain in production without dependency reviews or updates. Teams prioritize feature development over maintenance work, postponing library migrations indefinitely. package-lock.json locks in old request version preventing even accidental updates. No regular schedule for reviewing and updating dependencies means vulnerable, unmaintained packages accumulate technical debt and security risk over time.

Legacy Code Not Migrated to Modern HTTP Libraries

Applications contain legacy codebases built when 'request' was the de facto standard HTTP client library (2010-2019). Large applications with hundreds of request() calls across many files face significant migration effort. Code uses request-specific features like convenience methods (request.get, request.post), streaming interfaces, or cookie jars that require careful refactoring when migrating. Teams lack resources or prioritization to modernize working code even when using deprecated libraries. Fear of introducing bugs during migration leads to postponing updates. No automated migration tools or codemods available to simplify transition from request to modern alternatives.

Lack of Dependency Security Auditing Processes

Development teams don't regularly audit dependencies for security vulnerabilities or deprecation status. No use of npm audit, Snyk, or GitHub Dependabot to identify vulnerable or deprecated packages. Security scanning not integrated into CI/CD pipelines allowing vulnerable dependencies to be deployed to production. Teams unaware that 'request' is deprecated and contains security vulnerabilities because no automated alerting exists. Security reviews focus on application code but skip dependency analysis. Organizations lack security policies mandating regular dependency audits or defining response procedures when vulnerabilities are discovered in third-party libraries.

Missing Automated Dependency Update Processes

No automated processes to keep dependencies current and secure. Teams don't use Dependabot, Renovate, or similar tools that create pull requests for dependency updates. Manual dependency updates happen irregularly when developers remember or when specific vulnerabilities are publicized. package.json version ranges use exact versions (request@2.88.0) instead of ranges (^2.88.0) preventing minor/patch updates. No regular dependency update schedule (weekly, monthly) built into development workflow. Organizations treat dependency updates as optional rather than critical security maintenance, allowing deprecated libraries to persist for years.

Insufficient Third-Party Library Security Policies

Organizations lack formal security policies governing third-party library usage, approval, and lifecycle management. No requirements to use actively maintained libraries or avoid deprecated packages. No approval process for adding new dependencies or security review before adoption. Missing policies defining maximum age for dependencies or requiring migration when libraries are deprecated. Security team not involved in dependency decisions - developers choose libraries based on popularity or convenience without security evaluation. No centralized tracking of all dependencies used across organization's applications. Absence of policies means teams independently make decisions about using deprecated or vulnerable libraries.

Fixes

1

Migrate to Modern HTTP Client Libraries

Replace deprecated 'request' library with actively maintained alternatives. Use axios for feature-rich HTTP client with interceptors, automatic transforms, and good TypeScript support: const axios = require('axios'); const response = await axios.get(url). Use node-fetch for minimal fetch API implementation compatible with browser fetch: const fetch = require('node-fetch'); const response = await fetch(url). For Node.js 18+, use native built-in fetch API requiring no dependencies. Use got for advanced features like retry logic, streams, and HTTP/2 support. Create abstraction layer wrapping chosen HTTP client to simplify future migrations. Systematically replace all request() calls: search codebase for require('request'), request.get, request.post patterns and refactor to modern equivalents.

2

Implement Regular Dependency Security Auditing

Establish regular dependency security auditing processes integrated into development workflow. Run npm audit or yarn audit before every deployment to identify known vulnerabilities. Use Snyk, WhiteSource, or GitHub Advanced Security for continuous dependency monitoring with automated alerts. Configure CI/CD pipelines to fail builds when high/critical vulnerabilities detected: add npm audit --audit-level=high to pipeline. Schedule weekly/monthly dependency review meetings to assess security advisories and plan updates. Create security champions within teams responsible for monitoring dependency health. Document procedures for responding to vulnerability disclosures including assessment, patching, and verification steps.

3

Integrate Automated Vulnerability Scanning Tools

Deploy automated tools that continuously monitor dependencies for vulnerabilities and deprecation. Enable GitHub Dependabot Security Updates to automatically create pull requests for security patches. Use Snyk integration in GitHub/GitLab to scan every pull request for vulnerable dependencies before merge. Configure npm audit in pre-commit hooks to catch vulnerabilities before code reaches repository: husky with npm audit --audit-level=moderate. Set up OWASP Dependency-Check or Retire.js for additional vulnerability scanning. Configure alerts to security team email/Slack when new vulnerabilities discovered. Generate regular reports showing dependency health metrics: average dependency age, number of outdated packages, vulnerability counts by severity.

4

Establish Dependency Update Maintenance Schedule

Create formal process and schedule for keeping dependencies current. Implement Dependabot or Renovate Bot to automatically create pull requests for dependency updates with configurable schedules (daily for security patches, weekly for minor updates, monthly for major versions). Reserve time in sprint planning for dependency maintenance work - treat updates as critical technical debt, not optional. Use semantic versioning ranges in package.json enabling automatic patch/minor updates: use ^1.2.3 instead of 1.2.3 for automatic minor updates within major version. Group related dependency updates into single PRs to reduce review overhead. Maintain CHANGELOG tracking dependency updates and migration notes for future reference.

5

Adopt Dependabot or Renovate for Automated Updates

Configure Dependabot (GitHub native) or Renovate Bot for automated dependency update management. Create .github/dependabot.yml configuring update schedules, grouping strategies, and auto-merge rules for trusted updates. Enable security updates for immediate patches when vulnerabilities disclosed. Configure update schedules: daily for security fixes, weekly for patches, monthly for minor/major updates. Group updates by dependency type: group all testing libraries together, all build tools together. Enable auto-merge for patch updates that pass CI/CD tests. Use Renovate for more advanced features like custom grouping rules, update scheduling, and monorepo support. Review and merge bot PRs promptly to keep dependencies current.

6

Implement Robust Error Handling in HTTP Client Code

When migrating from 'request' to modern libraries, improve error handling patterns. Use try/catch with async/await for clearer error handling: try { const response = await axios.get(url); } catch (error) { handleError(error); }. Implement retry logic for transient failures using axios-retry or got's built-in retry. Add request timeouts to prevent hung requests: axios.get(url, {timeout: 5000}). Validate response status codes and handle non-2xx responses appropriately. Log HTTP errors with context (URL, method, status code) for debugging. Implement circuit breaker pattern for external service calls to prevent cascade failures. Add monitoring for HTTP client errors to detect issues early.

Detect This Vulnerability in Your Code

Sourcery automatically identifies express.js deprecated request library usage and many other security issues in your codebase.