From b48eb17e17d65180fe60aa1de39628bdb631ae22 Mon Sep 17 00:00:00 2001 From: Wolfvin Date: Sun, 12 Jul 2026 12:06:06 +0700 Subject: [PATCH] fix(security): vuln-scan false positive from checking declared semver range instead of resolved version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _parse_bun_lock() collected packages from TWO sources: workspaces.dependencies (declared semver ranges from package.json, e.g. '^9.0.0') AND packages (resolved concrete versions from the lockfile, e.g. '9.0.2'). Both were fed into the same vulnerability-matching loop as if they were equally valid 'installed versions'. _compare_versions()'s _parse_ver() extracts leading digits per dot-separated segment via regex ^(\d+) — for '^9.0.0', the first segment '^9' has no leading digit (the caret isn't stripped), so it silently parses to 0. This makes '^9.0.0' compare as if it were '0.0.0', matching ANY ' 13, jsonwebtoken false positives (4) eliminated entirely. --- scripts/vulnscan_engine.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/scripts/vulnscan_engine.py b/scripts/vulnscan_engine.py index 53093316..d8398c44 100755 --- a/scripts/vulnscan_engine.py +++ b/scripts/vulnscan_engine.py @@ -3471,14 +3471,18 @@ def _parse_bun_lock(content: str) -> List[Tuple[str, str]]: except json.JSONDecodeError: return packages - # Extract from workspaces dependencies (top-level declared deps) - workspaces = data.get("workspaces", {}) - for ws_name, ws_data in workspaces.items(): - for dep_type in ("dependencies", "devDependencies"): - deps = ws_data.get(dep_type, {}) - for name, version in deps.items(): - if name and version: - packages.append((name, version)) + # Note: workspaces.dependencies/devDependencies are declared semver RANGES + # from package.json (e.g. "^9.0.0", "~1.2.0") — not concrete installed + # versions. They must NOT be checked directly against vulnerable_range: + # _is_version_vulnerable()/_compare_versions() parse a leading "^"/"~" as + # a non-digit, silently truncating "^9.0.0" to [0,0,0] and making the + # package match ANY "