Find and Fix a Vulnerable Dependency

PythonBeginner
Practice Now

Introduction

Applications depend on libraries written by other projects. A useful library can have a known weakness even when your own program appears to work. This DeskLite ticket client uses an affected version of the Python HTTP library Requests.

You will read a fixed offline advisory, update the package that the client actually imports, and check functionality and version records together. The isolated Python environment, installation cache, and two-advisory course snapshot are prepared. No package-management or Python programming experience is assumed.

Run the Client and Inspect Its Package

In this step, you will establish the client's current business behavior and locate its installed dependency.

A dependency is software your application uses. This client directly uses requests to make HTTP requests; Requests itself uses another library, urllib3, for parts of that work. That second relationship is a transitive dependency.

cd /home/labex/project/desklite-dependencies

.venv/bin/python is the prepared, isolated Python executable for this project. Its packages are separate from system Python. No activation command or global installation is needed. Run the supplied client as you ran a supplied program in the Git lab:

.venv/bin/python app.py

Expect the original ticket with title Printer offline. The program works before the security repair; a known dependency issue does not imply every request already fails.

pip manages Python packages. -m pip tells this same isolated Python to run its package manager, while show reads metadata without changing anything:

.venv/bin/python -m pip show requests urllib3

Find Name, Version, and Location. Requests should be 2.32.3, urllib3 2.2.2, and package locations should be inside this project's .venv. We will update this environment, not a different Python installation.

Read the Offline Advisory Finding

In this step, you will connect a scanner finding to the package version that needs attention.

The prepared course-deps launcher runs OSV-Scanner 2.7.0 against a fixed local snapshot dated 2026-10-28. This intentionally small snapshot contains two selected advisories for Requests and urllib3; it is a learning fixture, not the full current production vulnerability feed. The command makes no network request.

Give it the prepared lock record:

course-deps requirements.lock

Expect a line containing requests 2.32.3, GHSA-9hjg-9r4m-mvj7, CVE-2024-47081, and fixed: 2.32.4, followed by Security findings: 1. The two IDs name the same underlying issue in different advisory systems.

This advisory concerns possible credential leakage when certain specially crafted URLs interact with stored client credentials. You do not need to reproduce an attack or configure those credentials here. Your task is to install the provided compatible fix and preserve ordinary requests.

The command intentionally exits 1 when it finds a known issue. A CHECK ERROR means the scan could not complete and exits 2; it is not evidence of safety. A severity rating helps prioritize review, but does not show that this application has already been exploited.

The report gives a fixed version. Next you will connect that report to the files used for installation and reproducibility.

Distinguish Requirements from Installed State

In this step, you will read the pinned installation list and the record of the resolved environment.

cat requirements.txt

Each line has the form package==version. The double equals signs pin that package to one version. This course's list includes both the direct dependency and its resolved supporting packages so the installation can be reproduced offline.

Requests is pinned to 2.32.3. The scan reported 2.32.4 as the compatible fix available in the cache. Keep all unrelated lines.

cat requirements.lock

A lock record describes the exact resolved package versions. Here it is a simple, fully pinned requirements-format file. It initially agrees with the installation list. After the update you will regenerate it from the actual environment rather than claiming a package changed merely by editing text.

There are three distinct states: the intended versions in requirements.txt, the actual packages inside .venv, and the resolved record in requirements.lock. All must agree at delivery. The scanner reads the file you name; it does not automatically prove that a running application imports those versions.

The cache under /opt/labex-dependency-tools/wheels contains the prepared initial and fixed packages. You will install from that cache, so no online version search or dependency conflict solving is required.

Install the Compatible Fixed Version

In this step, you will update the installation list and install the fixed package into the real project environment.

nano requirements.txt

Change only requests==2.32.3 to requests==2.32.4. Preserve every other pin. Save with Ctrl+O, Enter, Ctrl+X.

Now use the same environment's package manager. install changes installed packages; -r requirements.txt reads the named installation list. --no-index disables online package indexes, and --find-links points pip to the prepared wheel files. A wheel is a prebuilt Python installation package:

.venv/bin/python -m pip install --no-index --find-links /opt/labex-dependency-tools/wheels -r requirements.txt

Pip should replace Requests 2.32.3 with 2.32.4, while unrelated pinned packages remain satisfied. Judge the named version change; progress messages can differ. Do not run plain system pip, because that could update a different environment.

.venv/bin/python -m pip show requests

Expect Version: 2.32.4 and a location inside this project's .venv. Saving the list alone would not establish this installed state. The client is a one-shot program that imports its packages on each run, so later requests will use the updated environment.

Regenerate the Lock Record

In this step, you will make the resolved version record describe the packages actually installed.

pip freeze prints the environment's installed package pins. The shell operator > writes that output into a file instead of the terminal, replacing the file's previous content. The destination here is specifically the project lock record:

.venv/bin/python -m pip freeze > requirements.lock

The command normally prints nothing because its output went into the file. Read it:

cat requirements.lock

Requests should now be 2.32.4; the other dependency versions should remain the same. Ordering or capitalization can vary without changing which packages are recorded.

Check package compatibility with pip check, which checks declared dependency relationships:

.venv/bin/python -m pip check

Expect No broken requirements found. This checks package compatibility, not the application's business behavior or every possible vulnerability.

You now have consistent installation intent, installed packages, and a resolved record. The lock file is a real reproducibility artifact, not a copied report proving that a command was run. A valid equivalent method of producing the same accurate pins also satisfies the outcome.

Run the Functional Regression Check

In this step, you will confirm that updating the library preserved the original request and response.

A regression is previously working behavior that a change breaks. The course provides test.sh, a small functional check for the original client. You are learning to run this check; authoring tests comes later.

bash test.sh

Expect:

PASS: original ticket request and response.

The check actually runs the client against the local ticket service and compares the returned data. It does not treat a changed version string as business success.

Run the client yourself once more:

.venv/bin/python app.py

Expect the original ticket with ID 1 and title Printer offline. Neither deleting the client nor removing its dependency would preserve that behavior.

The library is updated on disk, and this newly started client imports it. Long-running applications may need their own controlled restart after dependency updates; this lab's client runs afresh each time. The final step rechecks the known issue using the accurate lock record.

Rescan the Delivered Dependency State

In this step, you will combine the fixed-snapshot scan with installed-package and business evidence.

Run the same offline scanner against the updated lock record:

course-deps requirements.lock

Expect No findings in the selected course snapshot. This specifically means the selected advisories no longer match the recorded versions. It does not establish that the snapshot covers every present or future issue.

Review the intended pin and actual installed package:

cat requirements.txt
.venv/bin/python -m pip show requests

Requests should be 2.32.4 in the file and environment; unrelated pins remain. The functional check from the previous step proves a different requirement: the updated client still performs its original request.

A complete repair needs both kinds of evidence. Editing only a manifest could leave the vulnerable installation in use. Updating an installation without recording it would make later reproduction unreliable. Skipping a scanner or deleting the dependency would hide evidence rather than repair the required application.

No investigation document or copied scanner report is required. Your deliverables are the actual updated package environment, accurate pinned records, and preserved business behavior.

Summary

You connected an offline advisory to a real installed Python dependency, installed a compatible fixed package from the prepared cache, and synchronized intended and resolved version records. A fresh scan and real functional request confirmed the targeted repair and preserved behavior within the explicit course-snapshot scope.