PySecScan is a lightweight and easy-to-use security scanning tool for Python projects. With a simple YAML configuration, it seamlessly integrates into any workflow, regardless of the framework or dependencies used. PySecScan automates security checks, linting, and SBOM generation, ensuring a proactive approach to code security with minimal setup.
-
Ensure you have Python 3.12 or higher installed on your system. You can download it from the official Python website.
-
Install PySecScan using pip or uv:
pip install py-secscan # Or using uv uv add --dev py-secscan
-
Create a sample Python project and navigate to its root directory.
-
Define the
.py-secscan.conf.yml
configuration file like this:version: "1" packages: - command_name: "echo" command_args: ["test"]
-
Run the security scan:
py-secscan scan
-
Output
[INFO] Subprocess command: <path>/.venv/bin/python -m ensurepip --upgrade
[INFO] Subprocess command: <path>/.venv/bin/python -m pip install -r <path>/.py-secscan/requirements.txt
[INFO] Execute builtins packages
[INFO] Executing package ruff
[INFO] Subprocess command: ruff check --fix
All checks passed!
[INFO] Package ruff completed
[INFO] Executing package cyclonedx-py
[INFO] Subprocess command: cyclonedx-py environment --outfile sbom.json <path>/.venv
[INFO] Package cyclonedx-py completed
[WARNING] python package is disabled
[INFO] {'logger_filepath': '<path>/.py-secscan/logs/py-secscan.2025-02-12.log', 'status': {'ruff': 'completed', 'cyclonedx-py': 'completed', 'python': 'disabled'}}
[INFO] Execute packages
[INFO] Executing package echo
[INFO] Subprocess command: echo test
test
[INFO] Package echo completed
[INFO] {'logger_filepath': '<path>/.py-secscan/logs/py-secscan.2025-02-12.log', 'status': {'ruff': 'completed', 'cyclonedx-py': 'completed', 'python': 'disabled', 'echo': 'completed'}}
The py-secscan
command currently has the following options:
scan
: Loads the .py-secscan.conf.yml
configuration and executes the defined commands. The security scan is, of course, proportional to what you define. By default, a linting check is performed, and the SBOM file is generated.
view
: Launches a web page based on Streamlit to visualize the SBOM and any detected vulnerabilities (if builtins.sbom_vulnerabilities
is enabled). To use this command, you must install streamlit manually or via pip install 'py-secscan[view]'
(recommended choice).
You can increase the verbosity level using the
-v
and-vv
options.
IN PROGRESS
IN PROGRESS
flowchart TD
A(["Your Python Project"]) -- define ---> C[".py-secsca.conf.yml"]
PySecScan(["$ py-secscan scan"]) -- run ---> Process
Process -. load ..-> C
Process -- check/setup --> Env
Process == exec ===> Subprocess["Subprocess
(builtins / packages)"]
Subprocess == stdout/stderr ===> Output
Subprocess -. save: FAILED or COMPLETED ..-> ExecutionStatus["Execution Status"]
Process -. save: RUNNING or DISABLED ..-> ExecutionStatus
Subprocess -. use ..-> Env["Virtual Environment"]
Output == next: subprocess ==> Process
The functionality of PySecScan is simple: using the .py-secscan.conf.yml
configuration file, you can define the security scanning strategy for your project.
Builtins:
By default, the py-secscan scan
command performs a project check using ruff
and creates the SBOM file using cyclonedx
. Additionally, you can enable sbom_vulnerabilities
to scan each package listed in sbom.json
using the OSV API.
Packages:
Once the builtins are executed, the scan retrieves the defined packages
and runs them one by one (installing them in the virtual environment first if defined). It is recommended to execute only Python packages related to security checks, but any type of binary can be executed as it runs as a subprocess (be mindful of FORBIDDEN_OPERATORS
, which prevent the execution of certain commands).
* Package installation is limited to Python packages available on PyPI.
The .py-secscan.conf.yml
configuration file must contain at least the version
key and is structured into several optional sections to customize py-secscan
's behavior. For more details view jsonschema version 1
1. Version:
version
(required): A string that defines the parser version to use. Currently supported versions:1
.
2. Options:
debug
(default: false | optional): Enables debug mode.env
(default: {} | optional): Dictionary of environment variables.pysecscan_dirpath
(default: ".py-secscan" | optional): Path to the PySecScan directory.venv_dirpath
(default: ".venv" | optional): Path to the virtual environment directory.enabled
(default: true | optional): Enables/disables security checks.disable_builtins
(default: false | optional): Disables all built-in commands.disable_venv_check
(default: false | optional): Disables the virtual environment check, allowing execution in a non-virtual environment.disable_venv_creation
(default: false | optional): Disables automatic virtual environment creation.disable_venv_install
(default: false | optional): Disables the installation of packages defined in thepackages
directive in the virtual environment.additional_forbidden_commands
(default: [] | optional): Additional list of forbidden commands that will be blocked.
3. Packages:
List of commands to execute.
command_name
(required): Name of the command to execute.command_args
(default: [] | optional): List of string arguments to pass to the command.install
(default: {} | optional):enabled
(default: false | optional): If true, the package will be installed automatically.package_name
(default: "" | optional): Used to define the package name for installation viapip install <package_name>==<version>
. If not defined, it defaults tocommand_name
.version
(default: "latest" | optional): Package version.extras
(default: [] | optional): Extra installation options.
enabled
: If false, the package will not be executed and will be marked asDISABLED
.on_error_continue
: If true, errors will not stop the execution of subsequent packages.
4. Builtins:
Builtins are predefined packages that can be enabled/disabled or configured differently at any time.
The ruff
builtin automatically performs an initial linting check on the entire project.
ruff
:command_name
: "ruff"command_args
: ["check --fix"]enabled
: Trueon_error_continue
: False
The cyclonedx
builtin automatically scans the virtual environment and generates an SBOM file containing all dependencies.
cyclonedx
:command_name
: "cyclonedx-py"command_args
: [ "environment --outfile sbom.json <venv_path>" ]enabled
: Trueon_error_continue
: False
The sbom_vulnerabilities
builtin, when enabled, scans for vulnerabilities in each dependency listed in the SBOM file using the OSV API.
sbom_vulnerabilities
:command_name
: "python -m py_secscan.modules.builtins.sbom_vulnerabilities"command_args
: ["sbom.json sbom_vulnerabilities.json"]enabled
: Falseon_error_continue
: True
A virtual environment (venv) must be present at the specified path and activated before executing the py-secscan scan
command. Before execution, a check ensures that the correct venv is being used (default: <project-path>/.venv
).
Once verified, all defined packages with install.enabled: true
are installed. A .py-secscan/requirements.txt
file is created, containing the list of packages installed at runtime by PySecScan.
This allows you to destroy the venv without worrying about losing installed packages since they will always be reinstalled based on the configuration.
β οΈ WARNING: Disabling the virtual environment check is possible but not recommended, as it could lead to installing packages globally. This should be used only in CI/CD contexts by settingoptions.disable_venv_check
totrue
.
As shown in the diagram, every execution of a builtin
or package
is a Python subprocess. The executed command is sanitized and checked to prevent harmful commands. Each execution status is recorded as RUNNING
, COMPLETED
, FAILED
, or DISABLED
.
-
Add to the
.py-secscan.conf.yml
configuration:... builtins: sbom_vulnerabilities: enabled: true
-
After also enabling the built-in
sbom_vulnerabilities
and running thepy-secscan scan
command, two new files are created in the root of your project:sbom.json
andsbom_vulnerabilities.json
. -
Run the command to view the SBOM files from a web page (remember, you must have py-secscan[view] installed):
py-secscan view
git clone https://github.com/FabrizioCafolla/py-secscan
cd py-secscan
Requirements:
Package | Version | Install Guide |
---|---|---|
devbox | >=0.12.0 |
docs |
Steps:
devbox shell
devbox run setup
Requirements:
Package | Version | Install Guide |
---|---|---|
python | >=3.12.0 |
downloads |
uv | >=0.4.3 |
docs |
Steps:
uv venv --python 3.12
source .activate
uv sync --all-extras
uv run pre-commit install
uv run pre-commit run --all-files
py-secscan -v scan
devbox run test
uv run pre-commit run --all-files
uv run pytest tests/*
py-secscan -vv scan