Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .claude/skills/prisma-taurus/vulnerability_history.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ The build-time coupling is real but narrower than first thought: `setup.py` does
- *Update (2026-06-30, scan #170 / branch-builder #572):* npm **11.18.0** (now latest) **does** bundle undici **6.27.0**, so on an *uncached* rebuild `npm i -g npm@11` clears these four. **Caveat learned this run:** in a `taurus-branch-builder` build, the `npm i -g npm@11` step (`#9`) sits *before* the layer a typical OS/apt fix changes, so Docker **reuses the cached `#9` layer** and undici stayed 6.26.0 in the branch scan even though the latest npm now bundles 6.27.0. Don't read "still 6.26.0 in the branch scan" as "npm hasn't fixed it" — verify what the *latest* npm bundles (npm/cli lockfile) and expect it to clear on the next no-cache master build. It remains a monitor item (no Dockerfile change needed). **Terminology (added 2026-08-20):** once the latest npm *does* bundle the fix, this stops being **monitor** and becomes **R (rebuild-clearable)** — the fix exists and the existing `npm i -g npm@11` installs it on rebuild. Monitor = no reachable fix exists yet; R = the fix exists and an unpinned line already picks it up. Same no-code-change action, different reason — and only R clears on a rebuild.
- *Update (2026-08-20, scan #203):* the monitor list **grew** — `/usr/lib/node_modules/npm/node_modules/` now flags `ip-address` 10.2.0 (CVE-2026-69192 **high 7.7**, CVE-2026-69198, CVE-2026-54272 → need 10.3.1), `brace-expansion` 5.0.7 (CVE-2026-14257 **high 7.5**, CVE-2026-69152 → need 5.0.9), `undici` 6.27.0 (CVE-2026-16728/16729/15157 → need 6.28.0) and `tar` 7.5.19 (GHSA-r292-9mhp-454m → need 7.5.21) — 9 findings, 2 of them high. **Checked both npm `11.19.0` (latest 11.x) and npm `12.0.2` (latest overall): both still bundle every one of those vulnerable versions.** So **do NOT bump the Dockerfile's `npm i -g npm@11` to `npm@12` hoping to clear them** — it changes nothing here and drags in a major npm upgrade for no CVE benefit. These are the single largest actionable-looking-but-not-actionable group in a modern scan; re-check the lockfile each run before spending time on them.
- *Update (2026-08-27, scan #216) — the #203 monitor group flipped to **R**.* npm **11.19.1** (published 2026-08-26 21:47Z) bundles **ip-address 10.5.0**, **tar 7.5.22**, **undici 6.28.0** and **brace-expansion 5.0.9** — every version the #203 note was waiting on. The existing `npm i -g npm@11` picks all of them up on an uncached rebuild, clearing 8 CVEs (incl. CVE-2026-69192 high 7.7 and CVE-2026-73566 high 7.5) with **zero code changes**. (8, not 9: there are 9 distinct CVEs at this path, but CVE-2026-14257 also occurs at the Mocha path, so the npm bump clears only its **npm-internal** occurrence and the CVE persists via Mocha — see the brace-expansion deferral below.) The scanned image had npm 11.19.0 and the old set. **npm 12.0.2 (released 2026-07-29, before 11.19.1) still bundles the vulnerable versions** — so `npm@12` would *regress* this; the standing "don't bump to `@12`" advice below is now backed by a second, stronger reason. Re-derive this each run from the lockfile; the `@11` tag moving is what does the work, not a Dockerfile edit.
- *Update (2026-09-21, scan #257) — undici is back to **monitor**, a NEW trio.* `undici` **6.28.0** (the version npm 11.19.1 bundles, i.e. the one the #216 note called fixed) is now itself flagged by **CVE-2026-85024 / CVE-2026-19534 / CVE-2026-18540** (all low, CVSS 0), needing **6.28.1** (published 2026-09-04). Checked the lockfiles again: **npm 11.19.1 is still the newest 11.x and still bundles 6.28.0**, so `npm i -g npm@11` cannot clear these — **monitor, not R.** And `npm@12` remains the wrong move — this is the #216 *regression* reason re-confirmed on new data, not an additional one: **npm 12.0.2 bundles undici 6.27.0**, i.e. *older* than what `@11` already ships. *Re-check condition:* an npm 11.x release whose lockfile pins `undici` >= 6.28.1.

### Verify in the image before opening a PR
- A branch *can* be scanned before merge: `taurus-branch-builder` (`run_integration=true`, `push_docker=true`, `public_docker=false`, `PERFORM_PRISMA_SCAN=true`) builds the branch into `us.gcr.io/verdant-bulwark-278/taurus:<branch>-<build>`, runs integration, and prints a twistcli scan in the console. Use it to confirm each fix actually landed and the counts dropped **before** creating the PR. (Earlier history wrongly assumed no pre-merge image existed.)
Expand Down Expand Up @@ -476,6 +477,17 @@ Distinguish "already covered, image just predates the fix" from "genuinely stuck

*Worked example (2026-08-20, scan #203):* `libheif` 1.17.6-1ubuntu4.6 flagged (CVE-2026-62289, fixed in `1.17.6-1ubuntu4.7`). `libheif1` was already in the unpinned upgrade list, and the order of events on 2026-08-19 was: build **started 12:06:22Z** → image **pushed 12:30:07Z** → noble-security **published the fix 12:36:56Z**. The patch simply did not exist yet while the image was being built. Nothing was broken and no pin was warranted; the run correctly made **zero** repo changes. The image was then republished via **`taurus-community-master`** (#14895 — the *only* job that pushes to Docker Hub; `taurus-branch-builder` pushes to internal GCR only and cannot publish, and nothing can promote an existing image because the master job hardcodes `docker build --no-cache`). Scan #204 on the republished image confirmed **295 → 294**, libheif gone, nothing new.

*Worked example — a `needed` finding becoming R with NO image change and NO code change (2026-09-21, scans #244 vs #257).* Both scans read the **same image content** (`Image ID b10f3a36…`) with the same extraction method, four days apart. Two OS findings flipped `Fix Status` from **`needed` → `fixed in`** in that window:

```
CVE-2026-18649 gst-plugins-good1.0 1.24.2-1ubuntu1.5 needed -> fixed in 1.24.2-1ubuntu1.6
CVE-2026-1801 libsoup3 3.4.4-5ubuntu0.7 needed -> fixed in 3.4.4-5ubuntu0.8
```

On 09-17 they were correctly **monitor** (no fix existed). Ubuntu then published both fixes *later that same day* — gst-good at **11:43Z** (Security), libsoup3 at **16:22Z** — i.e. **after** the image was built (08:42Z) and even after it was pushed (09:28Z). Both packages are installed unpinned by the Playwright/GStreamer `apt-get install` — `gstreamer1.0-plugins-good` is named explicitly on its command line, while `libgstreamer-plugins-good1.0-0` and `libsoup-3.0-0` come in as `automatic` deps (all proven from the image's `/var/log/apt/history.log`) — so they satisfy every R condition and clear on the next `--no-cache` master build with zero code changes.

**The durable point: a monitor verdict has a shelf life of one run.** Do not carry last run's "no fix available" forward — re-run the category-4 gate against the *current* `Fix Status` on every OS finding each run, because the feed moves independently of both the image and the repo. This is also the cleanest possible illustration of why R is keyed on **build start**, not on the push or on "is it still flagged": nothing about the image changed, only the pocket did.

**Two diffing traps learned while confirming that (both produce phantom findings):**
1. **Never compare counts across extraction methods.** The master job's plugin printed `Found 295 vulnerabilities` for the same image whose `taurus.csv` had **294** rows — the Jenkins plugin aggregate, a twistcli `--details` table parse, and CSV rows don't count identically. Compare CSV to CSV. (The master job's scan is also undiffable: no table in the console, and `prisma-cloud-scan-results.json` is not archived — so re-run `prisma-cloud-ondemand-scan` on `unstable` to verify a republish.)
2. **Ignore `Path` when diffing temp-extracted jars.** `jmeter-plugins-manager` is unpacked to `/tmp/jmeter-plugins-manager-1.11.jar<random>.jar`, a name that changes every build. Keying a diff on `(CVE, package, version, path)` reported CVE-2025-48924 as simultaneously "gone" and "new". Key on `(CVE, package, version)`.
Expand Down Expand Up @@ -518,6 +530,12 @@ If they genuinely differ, **scan by digest** — pass `IMAGE_URL=blazemeter/taur

Also worth knowing: a merge to master can land mid-run and republish `unstable` underneath you (that is what happened here — master #14904 pushed while the first scan was in flight). Re-baseline against the new digest rather than reasoning from the older scan; classifications derived from a stale baseline produce phantom R findings.

⚠️ **SKILL.md step 2's validity rule is NOT sufficient to prove freshness — and a stale baseline drives WRONG EDITS, not just wrong counts (2026-09-21).** Step 2 accepts a scan that ran today *and* after the image push. Scan **#243 passed both tests and was still stale**: it ran 09-17 09:55Z, 27 min *after* #14908 pushed `unstable` at 09:28Z, yet returned `Image ID f5a76402…` — the same pre-republish image scan #242 had read at 08:04Z. The agent reused its earlier pull. Only the `Image ID` check catches this; timestamps cannot, because "ran after the push" says nothing about what the agent actually pulled.

What that would have cost, had #243 been taken as the baseline: it flags `aom` 3.8.2-2ubuntu0.1, `libinput` 1.25.0-1ubuntu3.6 and `perl` 5.38.2-3.2ubuntu0.4, whose fixes published 09-14…09-16 — i.e. **before** the 09-17 08:42Z build start. That is exactly the "published before build start and still flagged → not R → genuinely fixable" branch of the category-4 gate, so the run would have added three `--only-upgrade` entries. **All three findings are absent from the real image** (build #14908 had already picked them up), so every entry would have been inert, for CVEs that do not exist. Per this file's own takeaway, neither the build nor the branch re-scan can catch that — an inert entry and a working one look identical in a scan.

So: **resolve the live config digest and compare it against the CSV's `Image ID` BEFORE classifying anything**, not as an afterthought. When they differ, re-scan by digest (`IMAGE_URL=blazemeter/taurus@sha256:<manifest-digest>`, artifact `taurus@sha256.csv`) and classify from that — which is what #244 did on 09-17, and why #244 is the scan that agrees with today's #257 on image content (`b10f3a36…`) while the tag-based #243 does not.

### Baseline scan job can fail *after* twistcli succeeds — fall back to `taurus.json`
- The `prisma-cloud-ondemand-scan` pipeline can finish **FAILURE** even though the scan ran fine. Seen 2026-07-07, build #172: twistcli completed and printed the full vulnerability table, but the pipeline then died in its `write_to_csv` post-step with `java.lang.NullPointerException: Cannot get property 'repoTag' on null object` (`WorkflowScript:62`). Result: **no `taurus.csv` artifact was archived.**
- Don't treat that FAILURE as "scan broken / no data." Check the archived artifacts: twistcli writes `taurus.json` (its `--ci-results-file`) regardless, and it holds the same findings. Fetch `.../<BUILD>/artifact/taurus.json`.
Expand Down
Loading