Summary
When requirements.txt uses >= (e.g. numpy>=1.26.0), SC4 ignores the bound and reports all historical CVEs for that package, not just the ones affecting the bound version. The bound can be raised above the CVE-fixed release and the scanner still reports every old CVE.
Environment
- SkillSpector 2.1.3
- Scan command:
skillspector scan <path> --no-llm --format json
- Target:
requirements.txt (PEP 508 style)
Repro
Create a requirements.txt:
numpy>=1.26.0
Pillow>=10.4.0
scikit-learn>=1.5.0
httpx>=0.27.0
All four bounds are above the fixed versions of the CVEs the scanner reports.
Run:
Observed: 4× CRITICAL findings, each listing 2–10 historical CVEs that the bound should exclude.
Root cause
src/skillspector/nodes/analyzers/static_patterns_supply_chain.py lines 396–399:
m = re.match(r"^([a-zA-Z][a-zA-Z0-9._-]*)(?:\[.*?\])?\s*(?:([=<>!~]=?)\s*([\d.*]+))?", line)
if m:
name = m.group(1)
version = m.group(3) if m.group(2) in ("==", "<=") else None
results.append((name, version, i))
version is set to None for any operator other than == / <=. The None propagates to the OSV query, which then returns every advisory ever filed for the package, instead of the subset that applies to the bound.
Expected
For numpy>=1.26.0, the scanner should either:
- Query OSV with
version=1.26.0 and return only CVEs affecting that version, or
- Use a proper PEP 508 parser (e.g.
packaging.requirements.Requirement) to extract the lowest acceptable version and filter CVEs against the affected range.
Suggested fix
- Replace the ad-hoc regex with
packaging.requirements.Requirement(line).specifier.
- Pick the lowest valid version (e.g.
>=1.26.0 → 1.26.0) and query OSV with that version.
- Filter returned CVEs to those whose
affected range intersects the specifier's accepted set.
- (Optional) Add an inline-skip syntax (e.g.
# skillspector: ignore=SC4 reason=...) so users can whitelist known false positives.
Workaround
In our project we upgraded all >= bounds to versions clearly above the CVE-fixed releases and accepted the scanner noise as informational. The bound values are correct at install time; only the scanner output is wrong.
References
Summary
When
requirements.txtuses>=(e.g.numpy>=1.26.0),SC4ignores the bound and reports all historical CVEs for that package, not just the ones affecting the bound version. The bound can be raised above the CVE-fixed release and the scanner still reports every old CVE.Environment
skillspector scan <path> --no-llm --format jsonrequirements.txt(PEP 508 style)Repro
Create a
requirements.txt:All four bounds are above the fixed versions of the CVEs the scanner reports.
Run:
Observed: 4× CRITICAL findings, each listing 2–10 historical CVEs that the bound should exclude.
Root cause
src/skillspector/nodes/analyzers/static_patterns_supply_chain.pylines 396–399:versionis set toNonefor any operator other than==/<=. TheNonepropagates to the OSV query, which then returns every advisory ever filed for the package, instead of the subset that applies to the bound.Expected
For
numpy>=1.26.0, the scanner should either:version=1.26.0and return only CVEs affecting that version, orpackaging.requirements.Requirement) to extract the lowest acceptable version and filter CVEs against the affected range.Suggested fix
packaging.requirements.Requirement(line).specifier.>=1.26.0→1.26.0) and query OSV with that version.affectedrange intersects the specifier's accepted set.# skillspector: ignore=SC4 reason=...) so users can whitelist known false positives.Workaround
In our project we upgraded all
>=bounds to versions clearly above the CVE-fixed releases and accepted the scanner noise as informational. The bound values are correct at install time; only the scanner output is wrong.References
packaginglibrary: https://packaging.pypa.io/