CycloneDX / CycloneDX/cyclonedx-python

environment subcommand: flag to NOT inherited `PYTHONPATH`

未关闭
#1,045 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
Python
星标
390
派生
98
平均合并
2 天 23 小时
30 天内合并 PR
2

描述

## Summary

When `cyclonedx-py environment ` is invoked from a process that has
`PYTHONPATH` set, the `PYTHONPATH` is inherited by the subprocess that
`cyclonedx-py` spawns to enumerate `sys.path` of the target interpreter. As a
result, packages from outside the target venv appear in the generated SBOM -
packages that are not installed in the environment being scanned at all.

## Root cause (probably)

In cyclonedx_py/_internal/environment.py, the __path4python method spawns a
subprocess to read the target interpreter's `sys.path`:

```python
# cyclonedx_py/_internal/environment.py, __path4python()
res = run(cmd, capture_output=True, encoding='utf8', shell=False) # nosec
```

`subprocess.run` is called without an explicit env= argument, so it inherits the
full environment of the calling process including `PYTHONPATH`. When
`PYTHONPATH` is set in the caller (e.g. by a build tool, test runner, or task
runner that places its own packages there), those paths are prepended to
`sys.path` inside the spawned interpreter. The resulting path list is then used
by `importlib.metadata.distributions(path=...)` to discover packages, so any
package reachable via the inherited `PYTHONPATH` is included in the SBOM as if
it were installed in the target venv.

## Minimal reproducible example

```python
uv tool install cyclonedx-bom

# Create the venv to be scanned (install only 'requests')
uv venv /tmp/scan_venv
uv pip install --python=/tmp/scan_venv/bin/python requests

# Create a separate directory with an unrelated package visible via PYTHONPATH
uv venv /tmp/outer_venv
uv pip install --python=/tmp/outer_venv/bin/python flask

# Run cyclonedx-py with PYTHONPATH pointing at the outer package directory
PYTHONPATH=$(/tmp/outer_venv/bin/python -c "import sysconfig; print(sysconfig.get_path('purelib'))") \
cyclonedx-py environment /tmp/scan_venv -o /tmp/sbom.json

# Inspect the result -> 'Flask' (and its dependencies) appear in the SBOM
# even though it is NOT installed in /tmp/scan_venv
uv run python -c "
import json
data = json.load(open('/tmp/sbom.json'))
names = [c['name'] for c in data.get('components', [])]
print('flask in SBOM:', 'Flask' in names)
print('All components:', sorted(names))
"
```

Expected: SBOM contains only requests (and its dependencies).

Actual: SBOM also contains flask (and its dependencies), which were never
installed in the scanned venv.

## Why it matters

Any tool that invokes cyclonedx-py in-process or as a subprocess after setting
PYTHONPATH including build systems, task runners, and CI pipelines that add
their own directories to PYTHONPATH will silently produce an inaccurate
SBOM. The SBOM over-reports dependencies that are not actually present in the
scanned environment, which undermines the entire purpose of SBOM generation for
supply-chain auditing and compliance.

## Suggested fix

Strip PYTHONPATH (and, for robustness, VIRTUAL_ENV and PYTHONHOME) from the
environment passed to the subprocess in `__path4python`:

```python
import os

def __path4python(self, python: str, import_site: bool) -> list[str]:
cmd = [self.__py_interpreter(python),
'-c', 'import json,sys;json.dump(sys.path,sys.stdout)']
if not import_site:
cmd.insert(1, '-S')

# Explicitly clear env vars that would pollute the target interpreter's
# sys.path and cause packages from outside the target venv to appear in
# the discovered distributions.
clean_env = {
k: v for k, v in os.environ.items()
if k not in ('PYTHONPATH', 'PYTHONHOME', 'VIRTUAL_ENV')
}

self._logger.debug('fetch `path` from python interpreter cmd: %r', cmd)
res = run(cmd, capture_output=True, encoding='utf8', shell=False, env=clean_env)
...
```

## Environment

- Package version: cyclonedx-bom 7.3.0
- Python version: 3.10+
- Platform: Ubuntu 24.04

## Contribution

- [x] I am willing to provide a fix
- [ ] I will wait until somebody else fixes it

贡献指南

打开贡献指南

调研方向

阅读 cyclonedx_py/_internal/environment.py,重点关注 __path4python 及其 subprocess 调用。运行 issue 中描述的最小 PYTHONPATH 复现,然后验证生成的 SBOM 只包含安装在被扫描虚拟环境中的软件包,并排除调用方环境暴露的软件包。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
cli, tooling
Issue 类型
缺陷
难度
2/5
预计耗时
1-3 小时
活跃度
冷清
描述清晰度
描述清楚
新手友好度
58/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。