Skip to content

fix: Validate --requirements path to prevent arbitrary file reads#5

Merged
Desperado merged 1 commit intoQuality-Max:mainfrom
itinance:fix/validate-requirements-path
Mar 26, 2026
Merged

fix: Validate --requirements path to prevent arbitrary file reads#5
Desperado merged 1 commit intoQuality-Max:mainfrom
itinance:fix/validate-requirements-path

Conversation

@itinance
Copy link
Copy Markdown
Contributor

Summary

Add validation to the --requirements CLI argument to ensure it points to a regular file that looks like a requirements file, preventing arbitrary file reads.

Problem

The --requirements pytest CLI argument accepts any file path without validation:

req_path = request.config.getoption("--requirements", default=None)
if req_path:
    p = Path(req_path)
    if p.exists():
        return p  # ← any readable file is accepted

This means a user (or a malicious CI configuration) could pass:

pytest --requirements /etc/shadow
pytest --requirements /home/user/.ssh/id_rsa
pytest --requirements /proc/self/environ

While the impact is limited (the contents are only parsed as pip requirement lines, not displayed in full), this still violates the principle of least privilege — the scanner should only access files it actually needs.

In automated CI/CD environments where the --requirements flag might be configured via environment variables or templates, an injection into the flag value could cause the scanner to read unintended files.

OWASP Reference

  • A01:2021 – Broken Access Control: The application does not restrict which files can be accessed via user-supplied input.
  • CWE-22 – Path Traversal: Accepting unvalidated file paths from external input.

Fix

Three validations are now applied:

  1. Path.resolve() — resolves the path to its canonical absolute form, eliminating .. traversal tricks
  2. p.is_file() — rejects directories, symlinks-to-directories, device files, and non-existent paths (replaces the previous p.exists() which accepted directories)
  3. Name check — rejects files that have no extension AND whose name doesn't start with requirements (e.g., /etc/passwd would be rejected, but requirements.txt, requirements-dev.txt, and constraints.txt are all accepted)
p = Path(req_path).resolve()
if not p.is_file():
    return None
if not p.suffix and not p.name.startswith("requirements"):
    return None
return p

Resolve the path and verify it is a regular file. Also reject paths
that don't look like requirements files (no extension and name doesn't
start with "requirements") to limit the scope of file access.
@Desperado Desperado merged commit 8213ff5 into Quality-Max:main Mar 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants