Vulnerability scan misses advisories affecting versions allowed by the declared constraint #39
Labels
No labels
bug
contribution welcome
duplicate
enhancement
good first issue
help wanted
invalid
question
upstream
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Reference
marvin8/zaojun#39
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
zaojun's vulnerability data comes from the package-level PyPI JSON endpoint (
/pypi/{package}/json). On that endpoint thevulnerabilitiesarray lists only advisories affecting the latest published release. Advisories that affect older versions — versions still permitted by the project's own declared constraint — are invisible to zaojun.So when the latest release is already fixed but the constraint still admits vulnerable versions, zaojun reports nothing: no advisory, no exit code.
Example
longwei 2.1.2 declared
httpx2[http2]~=2.3. Six advisories affect httpx2 2.3.0:Running zaojun 1.7.5 against longwei 2.1.2's
pyproject.tomlshows✅ httpx2~=2.3 is up to datewith no advisory output (exit 0 with the project'slibrary = trueconfig — but the gap is independent of library mode: a--no-libraryrun reports the compatible update and still no advisories).Live evidence (2026-09-13):
GET https://pypi.org/pypi/httpx2/json→ latest 2.12.0,vulnerabilities: []GET https://pypi.org/pypi/httpx2/2.3.0/json→ the six advisories aboveThe cached entry mirrors the empty list, so cache behaviour is faithful — the blind spot is in the data source, not the cache.
Impact
A constraint that admits known-vulnerable versions passes silently. In the longwei case the vulnerable-range signal came only from an external scanner (pysentry), which motivated the 2.1.3 floor bump to
~=2.12; zaojun's own scan gave no hint. Anyone auditing "does my declared range include vulnerable versions?" gets a false all-clear.Plan of attack:
>=,==,~=), fetch the version-level PyPI JSON for that lower-bound version ({index}/{package}/{version}/json) and read itsvulnerabilities. Cached under a distinct key (name@version) with the same 24 h TTL; indexes that don't serve per-versionvulnerabilitiesdegrade silently.range_vulnerabilities(non-withdrawn advisories affecting the lower-bound version) plus a suggested floor (max over advisories of their minimumfixed_in).needs_update=True, exit code 1. Independent of--libraryand--compat-ok: security is not update convenience.vuln-ignorerules apply to range advisories unchanged.2.3.0admits N advisories; raising the floor toXclears them); JSON gainsrange_vulnerabilities. README,docs/usage/*, andRelease-Notes.mdupdated (user-facing feature).Landing together with #37 and the Release-Notes reset recipe split in one branch/PR.
Closed by PR #41 (merged): range-advisory scanning implemented, dependency refresh + security re-verification done, Release-Notes reset recipe split out.