KAHIBARO
Discord Login Register

Dependency Vulnerabilities

Understanding Dependency Vulnerabilities

When you build backend applications, you almost always depend on external libraries and frameworks. These dependencies save you time, but they also import other people's code and, with it, other people's bugs and security issues.

This chapter explains how dependency vulnerabilities appear, why they are dangerous for a backend, and how to manage them in practice.

What Are Dependencies?

A dependency is any external package, library, or framework that your project needs in order to run.

Common types of dependencies for a backend:

TypeExample for Python backends
Web frameworkFastAPI, Django, Flask
Database driverspsycopg2, asyncpg, mysqlclient
ORMsSQLAlchemy, Tortoise ORM
Utility librariesrequests, httpx, pydantic, python-jose
Background workerscelery, rq
Cloud SDKsboto3, google-cloud-storage
Testing toolspytest, faker

Each dependency often has its own dependencies. This creates a dependency tree, also called the dependency graph.

Example requirements.txt:

text
fastapi==0.115.0
uvicorn[standard]==0.30.0
sqlalchemy==2.0.34
psycopg2-binary==2.9.9
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4

Installing these packages will pull in many more packages automatically. Any one of them can contain a vulnerability.

What Are Dependency Vulnerabilities?

A dependency vulnerability is a security weakness in one of the external packages you use. If your application uses a vulnerable version of a package, then your app is vulnerable too, even if your own code is perfect.

Typical examples:

A backend is only as secure as its weakest dependency version.

Even if the vulnerability is in a rarely used part of the library, an attacker may find a way to trigger it.

Sources of Dependency Vulnerabilities

  1. Coding mistakes in the library itself
    For example, forgetting to validate input or incorrectly using cryptography primitives.
  2. Unsafe defaults
    A library may ship with insecure default configuration, such as disabled certificate verification.
  3. Outdated algorithms or protocols
    For example, using MD5 or SHA1 for security, or old SSL/TLS versions.
  4. Transitive vulnerabilities
    A direct dependency depends on another vulnerable package. You do not see that package in your requirements.txt, but it is still in your environment.
  5. Malicious packages
    Sometimes an attacker uploads a package that looks similar to a popular one and contains malware.

Why Dependency Vulnerabilities Matter in Backends

Backends often:

That combination makes dependency vulnerabilities particularly dangerous.

Common Risk Scenarios

  1. Deserialization vulnerabilities
    A library that deserializes user input (for example pickles, XML, YAML) might allow attackers to execute code.
  2. Authentication and cryptography bugs
    If a dependency that handles tokens, passwords, or encryption is flawed, attacker may bypass authentication or decrypt data.
  3. Template injection
    An unsafe templating engine can allow user input to be executed as code if not properly sandboxed.
  4. File handling issues
    Libraries that handle ZIP, TAR, image files, or PDFs may allow directory traversal or arbitrary file writes.
  5. Command injection through wrappers
    A library that wraps shell commands incorrectly might let user input escape and run arbitrary commands on your server.

How Vulnerabilities Get Discovered and Disclosed

Most dependency vulnerabilities are discovered by:

Then they are usually:

Some key databases and sources:

SourceDescription
CVE databaseStandardized IDs for vulnerabilities
NVD (NIST)National Vulnerability Database with CVE details
GitHub Security AdvisoriesPackage specific advisories
PyPI advisoriesSecurity information for Python packages
Vendor blogsPosts from framework or library maintainers

Upgrading to the fixed version is usually the main mitigation.

Direct vs Transitive Dependencies

Understanding direct and transitive dependencies is important for assessing risk.

TypeDescriptionExample
Direct dependencyYou explicitly list it in your projectfastapi in requirements.txt
Transitive dependencyInstalled because a direct dependency needs itstarlette installed via fastapi

Example: dependency tree for fastapi (simplified):

text
fastapi==0.115.0
  β”œβ”€ starlette==0.37.0
  └─ pydantic==2.9.0
       └─ annotated-types==0.7.0

If there is a vulnerability in starlette or annotated-types, your application is still affected, even though you never added them manually.

You are responsible for vulnerabilities in all dependencies, including transitive ones.

Example: A Realistic Vulnerability Scenario

Imagine you use a JSON Web Token (JWT) library to verify access tokens:

python
from jose import jwt
def verify_token(token: str, secret: str) -> dict:
    payload = jwt.decode(token, secret, algorithms=["HS256"])
    return payload

Now suppose a vulnerability is discovered in this library:

An attacker can craft a token that bypasses signature validation and gets admin access.

Mitigation steps:

  1. Check if your version is affected.
  2. Read the advisory to understand impact and exploitation conditions.
  3. Upgrade to a safe version (for example 3.4.0 or later).
  4. Redeploy your backend.
  5. Consider revoking or rotating any long-lived tokens.

Tools for Detecting Dependency Vulnerabilities

You do not want to manually track security news for every package. Instead, use automated tools.

Ecosystem Specific Tools

For Python, typical tools are:

ToolPurpose
pip-auditScan your installed packages or requirements for known vulnerabilities using Python advisory DB
safetyCheck requirements against a vulnerability database
pip-toolsHelps manage pinned dependencies, not a scanner but essential for control

Example usage of pip-audit:

bash
pip install pip-audit
pip-audit

Sample output:

text
Found 1 known vulnerability in 1 package
Name     Version  ID         Fix Versions
-------  -------  ---------  ------------
requests 2.19.1   PYSEC-2018-99  >=2.20.0

You then update requests to at least 2.20.0.

GitHub and GitLab Dependabot and Security Scans

If your code is hosted on GitHub or GitLab, you can enable:

Typical workflow:

  1. Dependabot opens a pull request:
    • "Update urllib3 from 1.26.3 to 1.26.19"
    • Links to CVEs and advisories
  2. You review change, run tests, and merge if safe.

Good Practices for Managing Dependencies

Dependency management is one of the most important parts of backend security. Adopt these practices from the start.

1. Pin Versions

Always pin exact versions in your production dependencies instead of using unbounded ranges.

Bad:

text
fastapi
sqlalchemy>=2.0

Better:

text
fastapi==0.115.0
sqlalchemy==2.0.34

This ensures:

Use a separate file for development and testing dependencies, like:

2. Separate Direct Dependencies from Lock Files

A common pattern:

Tools like pip-tools or poetry can help with this.

Example with pip-tools:

requirements.in:

text
fastapi
uvicorn[standard]
sqlalchemy
psycopg2-binary

Generate the full list:

bash
pip-compile requirements.in

This produces a requirements.txt with all versions pinned, including transitive ones.

Always deploy with a fully pinned dependency list or lock file. Never deploy with floating versions in production.

3. Regular Dependency Updates

Do not wait years between updates. Instead:

A simple practice:

  1. Once a week, run:
bash
   pip-audit
  1. If vulnerabilities are found, upgrade the affected packages.
  2. Run tests and deploy.

4. Apply Security Patches Quickly

Treat security fixes differently from ordinary feature updates:

Many teams classify updates:

TypeResponse time target
Critical securitySame day or next business day
High severityWithin a few days
Medium / lowIn regular scheduled update window

5. Avoid Unmaintained Packages

Before adding a new dependency, check:

If a package has not been updated in many years, and there are open security issues, consider alternatives.

6. Minimize Dependencies

Each dependency is potential attack surface. Ask:

For example:

Less code from others often means fewer vulnerabilities for you.

Handling Vulnerabilities When They Are Found

At some point, you will discover that your project uses a vulnerable dependency. Have a simple playbook.

Step 1: Confirm and Assess

Even if you think it is unlikely, treat it as serious. Attackers might find exotic ways to reach vulnerable code.

Step 2: Update to a Fixed Version

Example:

bash
pip install "requests>=2.31.0" --upgrade
pip freeze > requirements.txt

Or with a tool:

bash
pip-compile --upgrade-package requests requirements.in

Step 3: Test and Deploy

Step 4: Post-Update Checks

Depending on the severity:

Preventing Malicious Package Attacks

Some attacks are not bugs but intentionally malicious packages. Common patterns include:

Defenses:

  1. Double check package names
    Verify you are installing the correct package, especially if you typed it by hand.
  2. Check the source repository
    Confirm the package points to a legitimate GitHub or similar repository.
  3. Avoid copy pasting random pip install commands from unknown sources
    Prefer official documentation.
  4. Pin versions and review updates
    If a popular package suddenly adds suspicious code, a code review of changes can catch it.

Dependency Vulnerabilities in CI/CD Pipelines

Your CI/CD system is a good place to integrate dependency security checks.

Typical pipeline steps:

  1. Install dependencies from the lock file.
  2. Run unit tests.
  3. Run security scans:
    • pip-audit or safety
    • Optional: secret scanning, static analysis
  4. Fail the pipeline if:
    • There are high or critical known vulnerabilities.
  5. Require a human to review and approve version changes.

This leads to a consistent rule:

Never deploy a backend that your CI pipeline reports as containing high or critical dependency vulnerabilities.

If you must deploy a temporary exception, document it and track it in your issue system.

Dependency Vulnerabilities and Containers

If you use Docker (covered later in the course), you also need to think about vulnerabilities in:

Common practices:

Your dependency stack becomes:

LayerExamples
Application codeYour Python files
Python dependenciesFastAPI, SQLAlchemy, requests
System librariesOpenSSL, libc, zlib
OS packagesDebian/Ubuntu/Alpine base image

Vulnerabilities can exist at any layer.

Summary

Dependency vulnerabilities are one of the main ways a backend becomes insecure. You must:

Managing dependencies well is a core responsibility of a backend developer, not just a task for security specialists.

Views: 8

Comments

Please login to add a comment.

Don't have an account? Register now!