requirements.txt - pip install requirements.txt - pip freeze requirements.txt

Hidden Dangers of Requirements.txt: How Dependency Pinning Can Save You

requirements.txt: Core Tool or Hidden Threat?

Every Python project has it. That innocent-looking requirements.txt sitting at the root of your repo, the file pip install requirements.txt consumes, is a list of dependencies, sure, but if you’re not careful, it can also be a wide-open door to unstable builds, vulnerable packages, and serious security issues.

At its core, requirements.txt controls what third-party packages your application pulls in. When you run pip install -r requirements.txt, Python’s package manager installs every dependency listed. But here’s the kicker: if you don’t pin exact versions, you’re trusting PyPI to always serve a safe, compatible, and unmodified version, every time. That’s not how modern AppSec works.

Without pinning, builds can break. Worse, your application might unknowingly ingest malicious packages. Open-ended versioning (Flask >=1.0, for example) or loose version constraints (django~=3.2) are fertile ground for injecting insecure code. This is why properly managing requirements.txt is a core security task.

Where pip freeze and pip install requirements.txt Breakdown

pip freeze is convenient, but also dangerous when used without understanding what it captures. Developers often generate requirements.txt using pip freeze requirements.txt, expecting it to lock down their environment. But freeze doesn’t validate the security or origin of the dependencies; it just dumps everything currently installed, including transitive and potentially outdated packages.

Now imagine a teammate, or your CI, blindly runs pip install -r requirements.txt. If that file includes deprecated, vulnerable, or even typo-squatted packages, you’ve just automated a security incident.

Quick example:

# Developer's freeze output
pip freeze > requirements.txt
boto3==1.24.20
requests==2.27.1

⚠️ Insecure example, do not use in production

Now add this to your CI pipeline:

- name: Install dependencies
run: pip install -r requirements.txt

You’re trusting that the environment is reproducible, that nothing has changed in PyPI, and that every dependency is still secure. That’s a huge assumption when relying on pip freeze requirements.txt workflows.

Real AppSec Threats: Typosquatting & Dependency Confusion in requirements.txt

Attackers love open-source ecosystems. Why? Because developers often rely on defaults and implicit trust. Here’s how they strike using requirements.txt:

  • Typosquatting: Uploading a malicious package with a name like requsts instead of requests. One character off and your build is owned.

requests  # ⚠️ Illustrative example, not a real package to install

  • Dependency Confusion: If your internal package isn’t pinned or privately scoped, attackers can publish a malicious version to PyPI with the same name. If your CI doesn’t validate sources, you’ll install their package instead of yours.

Both attacks exploit a lack of strict pinning and source control in requirements.txt. If yours just says some-internal-lib, and you run pip install requirements.txt in CI, it might fetch the wrong package from the wrong place.

Securing requirements.txt in CI/CD Pipelines with Hashes and Pinning

Here’s how to harden requirements.txt against real-world threats:

  • Pin exact versions: Always use == for every package in your requirements.txt. No wildcards, no ranges.
  • Use –require-hashes: This makes pip install -r requirements.txt verify the integrity of every downloaded package.

Example:

flask==2.2.5 \
--hash=sha256:<actual_hash_here> 

⚠️ Demonstrative example, replace with real hash in actual projects

  • Isolate your builds: Always build in clean, minimal containers. Never trust the base image blindly.
  • Use a private PyPI index: Host your own proxy/cache and mirror only trusted packages.

Run dependency scans: Integrate tools like pip-audit or use SBOM-based analysis in your pipelines.

Example GitHub Actions snippet:

- name: Secure install
  run: pip install --require-hashes -r requirements.txt

⚠️ Educational pipeline example,adapt to your environment

Strict handling of pip install -r requirements.txt in CI/CD is one of the easiest ways to reduce open-source risk.

Reproducible Builds: Keeping Them Stable Across Environments

If your app works locally but fails in staging or prod, inconsistent dependencies in requirements.txt are the usual suspect. Even a small version drift causes big problems.

Use these strategies:

  • pip-tools: Use pip-compile to generate requirements.txt from a requirements.in. It resolves dependencies with proper pinning.
  • Environment markers: For OS-specific packages or Python version-specific dependencies, use markers like platform_system == ‘Linux’.
  • Docker caching: In CI, cache your Docker layers after installing dependencies from requirements.txt to reduce build variability.

Example with pip-tools:

# requirements.in
flask

# Compile
pip-compile requirements.in

⚠️ Demonstrative example, actual output depends on your environment

The output is a fully pinned requirements.txt.

Tools like pip freeze, when combined with pip install -r requirements.txt during builds, require discipline and additional safeguards.

Conclusion: Locking Down Your requirements with Confidence

Mismanaging requirements.txt isn’t just bad practice; it’s an active security risk. Loose pinning, unverified installs, and blind trust in open registries are how attackers exploit your CI/CD pipeline. These aren’t theoretical flaws; they’re exploited daily.

Dependency pinning is more than a best practice. It’s your first line of defense against supply chain attacks in Python. Combine that with –require-hashes, build isolation, and reproducible tooling like pip-tools, and you get a pipeline that’s harder to compromise.

Whether you’re using pip install requirements.txt locally or in CI, always verify and monitor what goes into your builds. Tools like Xygeni provide visibility, policy enforcement, and automated checks that lock down your Python supply chain from pip freeze requirements.txt all the way through production.

sca-tools-software-composition-analysis-tools
Prioritize, remediate, and secure your software risks
7-day free trial
No credit card required

Secure your Software Development and Delivery

with Xygeni Product Suite