Skip to main content

Non-upgradable dependencies

Need

Explicitly declare and manage dependencies in the source code

Context

  • Usage of Python 3 for scripting and software development
  • Usage of Django for building web applications in Python
  • Usage of psycopg2 for connecting to and interacting with PostgreSQL databases

Description

Non compliant code

# File: requirements.txt

Django
psycopg2

The code above represents a requirements.txt file for a Python Django backend application. This file is used to manage Python package dependencies for the project. However, this file is currently vulnerable because it does not specify the exact versions of the dependencies that the project requires.

In this case, the dependencies are Django and psycopg2, but their versions are not explicitly declared. This means that when this file is used to install dependencies, it will always install the latest versions of these packages. While this may seem like a good thing, it can actually lead to several problems:

  1. Incompatibility Issues: New versions of packages can introduce breaking changes. This means that your code may no longer work as expected if a new version of a dependency is incompatible with your code.

  2. Security Risks: If a version of a package that you are using has a known security vulnerability, it may be fixed in a newer version. However, if you don't specify the version of the package, you could be unknowingly using a version with a known vulnerability.

  3. Lack of Reproducibility: If you do not specify the versions of your dependencies, it can be very difficult to reproduce your development environment elsewhere (like another developer's machine, or a build server) because the versions of the dependencies may be different.

Therefore, to fix this vulnerability, you should always specify the exact versions of your dependencies in your requirements.txt file.

Steps

  • Identify the exact versions of the dependencies that the application is currently using.
  • Modify the requirements.txt file to specify the exact versions of each dependency. For example, instead of 'Django', it should be 'Django==3.1.7' and instead of 'psycopg2', it should be 'psycopg2==2.8.6'.
  • Commit and push the changes to the repository.
  • Ensure that the application still works as expected with the specified versions of the dependencies.
  • Regularly review and update the dependencies to their latest stable versions to get the latest features and security updates.

Compliant code

# File: requirements.txt

Django==3.1.7
psycopg2==2.8.6

The original code was vulnerable due to the lack of explicit declaration of the versions of the dependencies. This could lead to potential issues such as unexpected breaking changes when the dependencies are updated, or security vulnerabilities if outdated versions are used.

The fixed code specifies the exact versions of the dependencies that the application is currently using. This is done by appending =={version} to the name of each dependency in the requirements.txt file. For example, 'Django' is changed to 'Django==3.1.7' and 'psycopg2' is changed to 'psycopg2==2.8.6'.

This ensures that the application will always use the specified versions of the dependencies, preventing unexpected breaking changes due to updates. It also allows for easier tracking and updating of the dependencies, as the exact versions are clearly stated.

However, it is important to regularly review and update the dependencies to their latest stable versions. This is to take advantage of the latest features and security updates provided by the dependencies. The versions specified in the requirements.txt file should be updated accordingly whenever the dependencies are updated.

References