Dependency Alert Triage Report - jupyterlab-stack - 2026-08-16
Executive Summary
Nothing requires a fix today, and no verdict rests on an unresolved question. Two alerts are recommended for scheduled work: sanitize-html GHSA-vccv-cmxp-4j9h and vega-functions GHSA-m9rg-mr6g-75gm, both reachable from untrusted notebook content in the delivered product. The remaining 130 of 132 verdicts (98.5%) are recommended for deferral, with the evidence below.
Every open alert was retrieved and the count verified at 66. Each alert's reachability was analyzed against this project's own code and against the delivered artifact in vendor/jupyterlab/static/, then scored in both execution contexts the project declares. Exploitation evidence came from KEV (the CISA/VulnCheck catalog of vulnerabilities with confirmed exploitation in the wild) and EPSS (a daily model score estimating each vulnerability's probability of exploitation in the next 30 days, read as a percentile against all scored CVEs).
How many findings are exploitable and reachable in production right now? Zero. No alert has all three rubric factors present, and no policy floor activated on any of the 132 verdicts. Not one of the 66 advisories is in KEV, and none reaches the top-1% EPSS line.
How much noise did scoring remove? 130 of the 132 verdicts scored, or 98.5%, are recommended for deferral as not reachable or not exploitable here. At the alert level that is 64 of 66 alerts deferrable in both contexts. Every open alert was scored, deferrals included, so the denominator is the full set. Focus can be directed elsewhere.
A risk-to-SLA policy was supplied (SafeCo ISP-07 v1.0), but it dates its clock from the alert's opening date in the tracking tool and the alert list carries no open date. No expiry date can be resolved, so no finding can be shown as past due. The remediation window each finding's residual risk earns is stated per entry and in the scores appendix.
The reachability and exploitability analysis retired 7,860 of 10,560 inherent NIST risk points (74.4%), recommended deferral on 130 of 132 verdicts, and moved 130 verdicts from a High inherent band to a Low residual band, with the remaining 2 falling from High to Moderate.
| Bucket | Count | Meaning |
|---|---|---|
| FIX_TODAY | 0 | Fix now |
| REVIEW | 0 | Unresolved question; investigate before deciding |
| SCHEDULE | 2 | Fix on a planned horizon; SLA below |
| DEFER | 130 | No action needed; evidence below |
Counts are verdicts. Each of the 66 alerts was scored once per execution context, giving 132 verdicts across 66 alerts.
Start with the two scheduled findings: both are sanitizer and renderer defects on the path that untrusted notebook content takes into the browser. The 130 deferral recommendations are backed by the evidence in the DEFER section below.
FIX_TODAY / REVIEW: act now or resolve the unknown
None. Nothing requires immediate action, and no verdict rests on unresolved evidence.
SCHEDULE: fix on a planned horizon
Here is what was found. Two advisories reach untrusted content through the delivered JupyterLab front end, and both paths were traced through this repository's own source and confirmed present in the shipped bundle: the sanitize-html scheme gate is applied to href and cite only while video[poster] is allowed, and the vega-functions modify and setdata expression functions are present verbatim in the delivered vega chunk. Neither advisory is in KEV. sanitize-html GHSA-vccv-cmxp-4j9h sits at EPSS percentile 0.035 (raw 0.0014) and vega-functions GHSA-m9rg-mr6g-75gm at percentile 0.090 (raw 0.0019), both far below the top-1% imminent-threat line. Neither has a resolvable deadline, because the supplied policy dates its clock from an alert-open date the alert list does not carry. Entries are ordered by SLA expiry, soonest first, with residual composite descending as the tiebreaker; with no resolvable expiry, the residual composite orders them and both sit at 50.
GHSA-m9rg-mr6g-75gm — a Vega chart from a notebook can run arbitrary JavaScript in the page — SCHEDULE
- Finding:
npm:vega-functions:GHSA-m9rg-mr6g-75gm(vega-functions 5.18.0, transitive throughvega ^5.20.0inpackages/vega5-extension/package.json, resolved byyarn.lock) - Why SCHEDULE: Exposure is present because the vulnerable code path was traced end to end from untrusted notebook output, and Impact is present on a tier_2 asset carrying confidential data. Threat is absent, which is the only reason this is not a fix-today item. Factor inventory: Threat absent, Exposure present, Impact present. No policy floor activated.
- Residual risk: Moderate, 50/100 (inherent High 80; 30 points retired)
- SLA expiry: ? — the policy allows 60 calendar days for a Moderate residual, counted from the alert's open date, and the alert list supplied no open date
- Evidence: Not in KEV. EPSS percentile 0.090, raw score 0.0019. The advisory names no configuration precondition and states explicitly that CSP-safe interpreter mode does not mitigate it. The delivered
@jupyterlab/vega5-extensionregistersrendererFactory.safe = trueforapplication/vnd.vega.v5+json, which is precisely the renderer rendermime uses for untrusted models, andRenderedVega.renderModelpasses the notebook's spec straight tovega.default(el, spec, ...)atpackages/vega5-extension/src/index.ts:139. The vulnerablemodifyandsetdataexpression functions are present in the shipped chunkvendor/jupyterlab/static/442.cafd6178a234483f.js, and installed 5.18.0 falls inside the affected range of anything below 6.1.1. The project's trust model names the notebook author as an untrusted actor who controls cell output payloads. - Recommended action: The fix is in vega-functions 6.1.1, which ships with the vega 6 line; no 5.x backport is published, so resolving this means moving
packages/vega5-extensionto a vega 6 release together with compatiblevega-embedandvega-liteversions. Where that is not yet available, the same exposure closes by not rendering untrusted Vega output at all, which the delivered configuration can do withjupyter labextension disable @jupyterlab/vega5-extension. Remediation belongs to the vendor's stack release, since the workstation does not upgrade components independently.
GHSA-vccv-cmxp-4j9h — a notebook can smuggle a javascript: URL past the HTML sanitizer — SCHEDULE
- Finding:
npm:sanitize-html:GHSA-vccv-cmxp-4j9h(sanitize-html 2.12.1, direct dependency of@jupyterlab/apputils, resolved byyarn.lock) - Why SCHEDULE: Exposure is present because the advisory's stated precondition holds in this configuration and the sanitizer sits directly on the untrusted-content path. Impact is present on a tier_2 asset carrying confidential data. Threat is absent. Factor inventory: Threat absent, Exposure present, Impact present. No policy floor activated.
- Residual risk: Moderate, 50/100 (inherent High 80; 30 points retired)
- SLA expiry: ? — the policy allows 60 calendar days for a Moderate residual, counted from the alert's open date, and the alert list supplied no open date
- Evidence: Not in KEV. EPSS percentile 0.035, raw score 0.0014. The advisory requires the application to allow a URI-bearing attribute that is not in
allowedSchemesAppliedToAttributes, and namesposteras one of the vectors. JupyterLab setsallowedSchemesAppliedToAttributes: ['href', 'cite']atpackages/apputils/src/sanitizer.ts:1220, deliberately dropping the default'src', and allowsvideo: [... 'poster' ...]around line 1009. The same string appears verbatim in the delivered bundlevendor/jupyterlab/static/jlab_core.8cf27f880e10219d.js. That sanitizer is the one applied to untrusted notebook HTML atpackages/rendermime/src/renderers.ts:48, one line beforehost.innerHTML = source. Theform[action]andbutton[formaction]vectors the advisory also names are closed: neither attribute is in the allowlist. - Recommended action: No fixed sanitize-html release exists; the advisory states every version from 1.18.0 through at least 2.17.2 behaves this way. The change that resolves it is local: add the URI-bearing attributes to
allowedSchemesAppliedToAttributesinpackages/apputils/src/sanitizer.tsso the scheme check runs on them, at minimumposter, or removeposterfromvideo's allowed attributes. Either edit putsjavascript:in that attribute back under thenaughtyHrefgate. Remediation belongs to the vendor's stack release.
DEFER: why these alerts are safely deferrable
This section is the evidence that each deferral was earned. The deferrals below were produced by the same analysis, to the same evidentiary standard, as the findings scheduled above: one process, one quality bar, different outcomes on different evidence.
The single fact that carries most of this section: the delivered JupyterLab component is a prebuilt front end. vendor/ contains the installed Python distributions and no node_modules directory anywhere. The only JavaScript that executes on an analyst's workstation is what is compiled into vendor/jupyterlab/static/*.js, and the rspack license plugin wrote the complete inventory of that bundle to vendor/jupyterlab/static/third-party-licenses.json. A package absent from that file is not on the workstation in any form.
Group 1: the vulnerable package never reaches a workstation (53 alerts, 106 verdicts)
These are bundlers, test runners, linters, and release tooling. In the delivered runtime they are not loaded (code_not_loaded) because they are absent from the bundle inventory; in the vendor build they run only on first-party input (no_attacker_controlled_input) under the attacker model the project's risk context states for that pipeline, which consumes a pinned upstream release commit and lockfile-pinned, integrity-verified registry packages, and no third-party or customer content.
Members, with alert counts: tar (13): archive extraction path traversal, symlink poisoning, and parser DoS. handlebars (8): template injection, prototype pollution, and AST type confusion. brace-expansion (4), minimatch (3), js-yaml (3), qs (3): pattern-expansion and parser DoS. svgo (2), serialize-javascript (2), tmp (2), ws (2): SVG script survival, CPU exhaustion, temp-file traversal, WebSocket memory disclosure. @octokit/plugin-paginate-rest, @octokit/request, @octokit/request-error (1 each): ReDoS in the GitHub release client. body-parser, engine.io, glob, ip, linkify-it, sigstore, uuid, yaml (1 each).
Residual band Low, composite 20, inherent 80, retired 60 on every verdict in this group. None is in KEV. EPSS percentiles run from 0.039 (tar GHSA-vmf3-w455-68vh) to 0.974 (lodash is in group 2; the highest here is ip at 0.944), with all but two below the p90 low-water mark for confident absence. Reachability finding in plain words: the vulnerable code is not imported, because it is not present on the machine.
Two of these deserve a note beyond the group rationale. ip GHSA-2p57-rm9w-gvfp: an SSRF categorization flaw. The risk context records that the workstation's inbound isolation says nothing about outbound reach, so an SSRF here would be a real pivot if the code ran; it does not, because ip arrives only through the release toolchain's proxy agents. sigstore GHSA-52v5-jr5w-gjxr: the certificateOIDs verification constraints are silently dropped, which weakens provenance checking in the release pipeline rather than exposing the delivered product. It is deferrable on reachability, and it is worth the vendor's attention as a supply-chain control question separate from this triage.
Group 2: the package is in the dependency graph, but the vulnerable module is not in the shipped bundle (2 alerts, 4 verdicts)
lodashGHSA-r5fr-rjxr-66jc: code injection through_.templateimportskey names. JupyterLab's own code imports onlylodash.escapeandlodash.mergewith, which are separate packages; thelodashpackage arrives transitively through @rjsf. The literal stringInvalid `variable` option passed into `_.template`does not appear in any file undervendor/jupyterlab/static/, so the template module was never bundled.vega-interpreterGHSA-7f2v-3qq3-vvjf: absent from the bundle inventory.vega-embedreadsvega.expressionInterpreterand falls back when it is undefined, visible in chunkvendor/jupyterlab/static/4402.a3418dcfee7961fa.js; no interpreter implementation ships.
Residual Low 20, inherent 80, retired 60 on both. Neither is in KEV. lodash GHSA-r5fr-rjxr-66jc is the highest-EPSS alert in the whole set at percentile 0.974 (raw 0.2133), which puts it in the p90–p99 gray zone and makes it the one to watch; vega-interpreter sits at 0.324.
Group 3: delivered and loaded, but the advisory's trigger precondition is absent (9 alerts, 18 verdicts)
This is the group where the vulnerable library genuinely runs in the browser on attacker-authored content, and the advisory still does not fire, because each one names a configuration or environment precondition this build does not meet. Every one was checked against the primary advisory text and then against the delivered artifact.
@jupyterlab/help-extensionGHSA-rch3-82jr-f9w9: the CommandLinker token-theft XSS is fixed at@jupyterlab/help-extension4.5.7 and notebook 7.5.6. The stack delivers JupyterLab 4.6.2 and notebook 7.6.1, both past the fix, and the patch is physically present as theallowCommandLinkertoggle inpackages/apputils/src/sanitizer.ts, inpackages/apputils-extension/schema/sanitizer.json, and in the deliveredjlab_corechunk and shipped schema. The alert fires only because the yarn workspace version reads0.0.0-use.local, which no semver range excludes.ajvGHSA-2g4f-4pwh-qvx6: the ReDoS needs the$dataoption. Both delivered ajv consumers were enumerated and neither enables it:packages/settingregistry/src/settingregistry.ts:263-267constructs{useDefaults: true, strict: false}and{strict: false}, and@rjsf/validator-ajv8's config is visible verbatim in the delivered chunk as{allErrors:!0,multipleOfPrecision:8,strict:!1,verbose:!0}. This matters because the project's risk context explicitly names extension-supplied settings schemas as attacker-controlled input to this pipeline, so the input is hostile; the option that would make it dangerous is off.dompurifyGHSA-c2j3-45gr-mqc4: the hook-policy gap needsCUSTOM_ELEMENT_HANDLINGenabled andafterSanitizeElementsused as a security layer. DOMPurify reaches the bundle only through mermaid.CUSTOM_ELEMENT_HANDLINGoccurs once in the entire bundle, inside DOMPurify's own option parsing, with no caller passing it.addHookoccurs twice, both mermaid, registeringbeforeSanitizeAttributesandafterSanitizeAttributes. Neither precondition holds.fast-uriGHSA-4c8g-83qw-93j6 and GHSA-v2hh-gcrm-f6hx: both are host-confusion parsing flaws whose harm is a policy-versus-use desync, which requires the application to make a host-based security decision on the parse and then hand the same string to a real fetcher. fast-uri's only delivered consumer is ajv, for JSON-Schema$idand$refresolution. No delivered code fetches or routes on a fast-uri-parsed host.lodashGHSA-f23m-r3pf-42rh: prototype pollution through array paths in_.unsetand_.omit. The only delivered call path is @rjsf/core'somitExtraDatahandling, andomitExtraDataandliveOmitappear nowhere in the JupyterLab source tree, so that form prop is never set.postcssGHSA-r28c-9q8g-f849: postcss 8.5.14 is delivered, pulled in by sanitize-html's style-attribute parsing, and it does parse attacker-authored CSS. The harm is a filesystem read inprevious-map.js. In the browser bundle those come from module3038, andvendor/jupyterlab/static/4550.097f83560a3b698b.jsdefines that module as an empty factory:{4320(){},3038(){},91190(){},7155(){},54318(){}}. Node'sfs,path, andsource-map-jsare all stubbed out. There is no filesystem to traverse.vegaandvega-expressionGHSA-7f2v-3qq3-vvjf: the advisory states two required conditions, and the first is that the application attaches the vega library and avega.Viewto the global window, the gadget beingVEGA_DEBUG. The stringVEGA_DEBUGdoes not occur, case-insensitively, in any file undervendor/jupyterlab/static/, including the vega core chunk and the vega-embed chunk. The delivereddist-stack/jupyter_lab_config.pyalso setsc.LabApp.expose_app_in_browser = False. The second condition, untrusted specs, does hold, so this one rests entirely on the absent global.
Residual Low 20, inherent 80, retired 60 on all 18 verdicts, except that postcss carries medium confidence on its residual because no KEV or EPSS record exists for CVE-2026-73646 and the Threat factor had no real signal. None is in KEV. EPSS percentiles: dompurify 0.061, fast-uri 0.171 and 0.316, vega and vega-expression 0.324, @jupyterlab/help-extension 0.391, ajv 0.401, lodash GHSA-f23m 0.727, postcss no record.
Group 4: the build-context verdict on the two scheduled alerts (2 verdicts)
sanitize-html GHSA-vccv-cmxp-4j9h and vega-functions GHSA-m9rg-mr6g-75gm are scheduled in the delivered runtime and deferred in the vendor build. In the build they execute against the vendor's own fixtures and test content under the attacker model the risk context states, so no_attacker_controlled_input applies there. Residual Low 20, inherent 80, retired 60 on both build verdicts. The runtime verdicts above are the ones that carry the work.
The boundary of these deferral claims
Two deferred alerts sit in the EPSS p90–p99 gray zone, which is elevated but below the top-1% imminent-threat line. lodash GHSA-r5fr-rjxr-66jc is at percentile 0.974, raw score 0.2133, and ip GHSA-2p57-rm9w-gvfp is at percentile 0.944, raw 0.0828. Both are monitor-worthy: the next EPSS retrain can push either past p99, and a KEV listing on either would activate the kev_emergency floor and move it to at least SCHEDULE regardless of reachability. Two more are approaching that zone and worth the same watch: glob GHSA-5j98-mcp5-4vw2 at 0.866 and handlebars GHSA-2w6w-674q-4c4q at 0.814.
Four deferred alerts have no threat record at all and rest on reachability alone: postcss GHSA-r28c-9q8g-f849, handlebars GHSA-442j-39wm-28r2, handlebars GHSA-7rx3-28cr-v5wh, and serialize-javascript GHSA-5c6j-r48x-rmvq. Their residual scores carry medium confidence for that reason. When KEV or EPSS records appear for them, re-score.
What would change any of these verdicts, derived from the rubric's factor math: every deferred alert here has Impact present on a tier_2 asset, so threat evidence appearing, meaning a KEV listing or a top-1% EPSS score, moves the base bucket from DEFER to SCHEDULE on its own. Separately, a change to the delivered build changes the reachability half: if a future stack release bundles a package that is absent today, or if the vendor enables $data on an ajv instance, sets CUSTOM_ELEMENT_HANDLING, or attaches vega to the global window, the corresponding deferral no longer holds. Re-score after any dependency or bundler-configuration change.
Next Steps
Address immediately. Nothing.
Investigate before deciding. Nothing. No verdict rests on an unresolved question.
Schedule. Two findings, both in the delivered front end's untrusted-content path. Neither has a resolvable policy deadline, because the alert list carried no open date; both earn a 60-calendar-day window from that date under SafeCo ISP-07 v1.0 for a Moderate residual. Supply the alert open dates to fix the deadlines.
npm:vega-functions:GHSA-m9rg-mr6g-75gm— movepackages/vega5-extensionto vega 6 with vega-functions 6.1.1 or later, or disable@jupyterlab/vega5-extensionin the delivered configuration.npm:sanitize-html:GHSA-vccv-cmxp-4j9h— inpackages/apputils/src/sanitizer.ts, either addposterand the other URI-bearing attributes toallowedSchemesAppliedToAttributesor dropposterfromvideo's allowed attributes.
Both changes belong to a vendor stack release. The risk context records that the workstation does not upgrade components independently, so a recommendation addressed to the analyst is not actionable.
No action; annotate the alert with the deferral rationale. 64 alerts, 130 verdicts. Record the rationale on each alert rather than closing it silently; see the dismissal-commands appendix.
Two follow-ups outside these 66 alerts. First, dist-stack/requirements.txt delivers notebook==7.6.1, jupyterlab_git==0.54.0, and nbdime==4.0.4 alongside JupyterLab, and each ships its own independently built front-end bundle resolved from its own lockfile. This triage is scoped to this repository's yarn.lock and says nothing about those three bundles. Second, the risk context records that one vulnerable delivered build ships to every customer workstation, so the two scheduled findings are fleet-wide, not per-instance.
Appendix: Triage metadata
This appendix is for the reviewer auditing how these verdicts were produced: who and what produced them, from what inputs, with what caveats.
Project: jupyterlab-stack
Date: 2026-08-16
Rubric: k9 Risk Scoring Rubric 2026.08.13-v26, workflow 2026.08.12-v33
Scored and reported by: claude-opus-5
Risk context: 2026-07-30+1c56417
SLA: SafeCo Vulnerability Management Policy ISP-07 v1.0, calendar days
Findings scored: 66 alerts (132 context-specific verdicts)
Each alert was scored in both execution contexts the risk-context file declares, one verdict per context, so the detail sections carry more verdicts than alerts. Both contexts include /yarn.lock in their paths, which is why every alert bound to both.
- Count verification: The supplied open-alert list held 66 entries. Scoring ran in seven
score_riskcalls;batch_stats.alerts_totalsummed to 66 (10 + 10 + 10 + 10 + 10 + 10 + 6) andbatch_stats.findings_totalsummed to 132, which is 66 alerts at 2 bindings each. Per-bucket counts summed to SCHEDULE 2 and DEFER 130. - Quality flags: None.
batch_stats.quality_flagswas empty on all seven calls.undetermined_fractionwas 0 anddefault_context_fractionwas 0 throughout; every verdict rests on a determined reachability call and on stated asset context rather than the rubric default. - Unbound alerts: None.
batch_stats.findings_without_context_bindingwas empty on every call. - Basis procedure: All 132 reachability determinations were made against basis-selection procedure 2026.08.05-v4;
distinct_basis_tokenswas 1 on every call. - Reachability basis histogram, across all 132 verdicts:
no_attacker_controlled_input66,code_not_loaded55,unreachable_from_entrypoint9,manual_call_graph2. - Policy directives: SafeCo ISP-07 v1.0 was read as untrusted evidence. Its authority here is the risk-to-SLA mapping in §4.1, the clock rule in §4.2, and the calendar-day basis. It contains no directive text instructing how to run the analysis, and it changed no verdict, bucket, reachability call, or NIST value. §3's instruction that the residual risk level governs remediation timeframes was applied as the mapping key, which is what it is for.
- Risk-context claims evaluated, not obeyed: The file states an attacker model for the
jupyterlab-buildcontext and instructs the reader not to re-derive it. That is a claim about the vendor's pipeline, and it was used as a value: build inputs are pinned and integrity-verified, so build-context reachability resolved tono_attacker_controlled_input. It is worth stating plainly that all 66 build-context verdicts rest on that declared model rather than on per-package tracing of the build. If the pipeline ever consumes third-party contributions or unpinned artifacts, those 66 verdicts need re-scoring. The file also records four facts the AssetContext enum cannot express, of which two changed the analysis: outbound network reach is wide even though inbound is isolated, which is why theipSSRF finding was checked on reachability rather than argued down on theisolatedvalue; and one vulnerable build reaches every customer workstation, which is noted in Next Steps. - Unresolvable SLA clocks: The policy dates its clock from the alert's opening date in the tracking tool. The supplied alert list carries no such date for any of the 66 alerts, so every SLA expiry renders
?. The remediation window each residual earns is still stated, so supplying the open dates is sufficient to resolve every deadline without re-scoring.
Appendix: Risk scores (NIST SP 800-30)
This appendix is for the reviewer and the engineer reconciling policy: every finding's scores, drivers, and deadlines.
Each verdict carries a risk_assessment rendering the finding on the NIST SP 800-30 scale, split into two values.
- Inherent risk: how bad this flaw would be if you assumed the worst, with attackers actively exploiting it and your code running the vulnerable path.
- Residual risk: what risk remains after checking the two things that usually are not true, whether attackers are really exploiting it and whether your code can even reach the vulnerability. This is the risk you are carrying now, and it is the number to report.
- Retired risk: the risk the analysis ruled out, measured as how far the number fell from inherent to residual.
The reachability and exploitability analysis retired 7,860 points (74.4% of the 10,560 inherent points across 132 verdicts), safely deferred 130 of 132 verdicts, and moved 130 verdicts from a High inherent band to a Low residual band, with 2 falling from High to Moderate.
This lets you map a k9 verdict to your own severity or priority scheme. k9 emits the score; you own the mapping.
Deadlines come from SafeCo ISP-07 v1.0, which maps the residual score to a remediation window: Moderate (21–79) gets 60 calendar days and Low (1–20) gets 180, counted from the alert's open date. The verdict stays the action signal. Every SLA Expiry cell reads ? because the policy applies but its clock has no resolvable start: the alert list supplied no open date. The Window column carries the days the policy allows, so a reader with the open dates can compute every expiry.
The NIST score is risk context, not an action signal. Anchor priority on the verdict and use the residual as a tiebreaker.
Rows are ordered by residual composite, highest first, then by EPSS percentile. vega and vega-expression share GHSA-7f2v-3qq3-vvjf with identical verdicts and evidence and are grouped into one row covering 2 alerts; vega-interpreter carries the same advisory on a different reachability basis and stays separate. Every other row is one alert. Unless a row says otherwise, both context verdicts are identical and the row states them once.
| Vuln ID | Package | Verdict | Driver | Residual risk | Residual | Inherent | Retired | Window | SLA Expiry |
|---|---|---|---|---|---|---|---|---|---|
| GHSA-m9rg-mr6g-75gm | vega-functions | SCHEDULE (runtime) | reachable (traced call graph) | Moderate | 50 | 80 | 30 | 60d | ? |
| GHSA-vccv-cmxp-4j9h | sanitize-html | SCHEDULE (runtime) | reachable (traced call graph) | Moderate | 50 | 80 | 30 | 60d | ? |
| GHSA-r5fr-rjxr-66jc | lodash | DEFER | vulnerable module not bundled | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-2p57-rm9w-gvfp | ip | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-5j98-mcp5-4vw2 | glob | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-2w6w-674q-4c4q | handlebars | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-f23m-r3pf-42rh | lodash | DEFER | no call site with attacker path | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-f5x3-32g6-xq36 | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-96hv-2xvq-fx4p | ws | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-rmvr-2pp2-xj38 | @octokit/request | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-58qx-3vcg-4xpx | ws | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-3mfm-83xf-c92r | handlebars | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-xhpv-hc6g-r9c6 | handlebars | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-9cx6-37pm-9jff | handlebars | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-xpqw-6gx7-v673 | svgo | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-h5c3-5r3r-rr8q | @octokit/plugin-paginate-rest | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-xx4v-prfh-6cgc | @octokit/request-error | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-34x7-hfp2-rc4v | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-3ppc-4f35-3m26 | minimatch | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-7r86-cg39-jmmj | minimatch | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-v6h2-p8h4-qcjw | brace-expansion | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-2g4f-4pwh-qvx6 | ajv | DEFER | $data option not enabled |
Low | 20 | 80 | 60 | 180d | ? |
| GHSA-rch3-82jr-f9w9 | @jupyterlab/help-extension | DEFER | delivered version carries the fix | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-w7fw-mjwx-w883 | qs | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-23c5-xmqv-rm74 | minimatch | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-qj8w-gfj5-8c6v | serialize-javascript | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-48c2-rrv3-qjmp | yaml | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-f886-m6hf-6m8v | brace-expansion | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-23hp-3jrh-7fpw | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-52cp-r559-cp3m | js-yaml | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-8x88-c5mf-7j5w | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-6rw7-vpxm-498p | qs | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-w8wr-v893-vjvp | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-mh29-5h37-fv8m | js-yaml | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-qffp-2rhf-9h96 | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-7f2v-3qq3-vvjf | vega, vega-expression (2 alerts) | DEFER | VEGA_DEBUG global absent |
Low | 20 | 80 | 60 | 180d | ? |
| GHSA-7f2v-3qq3-vvjf | vega-interpreter | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-4c8g-83qw-93j6 | fast-uri | DEFER | no host-policy consumer | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-r292-9mhp-454m | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-h67p-54hq-rp68 | js-yaml | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-q8mj-m7cp-5q26 | qs | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-ph9p-34f9-6g65 | tmp | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-r635-g3xr-vw7x | engine.io | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-3jxr-9vmj-r5cp | brace-expansion | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-v245-v573-v5vm | linkify-it | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-8qq5-rm4j-mr97 | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-mh99-v99m-4gvg | brace-expansion | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-w5hq-g745-h8pq | uuid | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-52f5-9888-hmc6 | tmp | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-gvwx-54wh-qm9j | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-xjpj-3mr7-gcpf | handlebars | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-83g3-92jg-28cx | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-2qvq-rjwj-gvw9 | handlebars | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-v422-hmwv-36x6 | body-parser | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-v2hh-gcrm-f6hx | fast-uri | DEFER | no host-policy consumer | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-9ppj-qmqm-q256 | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-2p49-hgcm-8545 | svgo | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-r6q2-hw4h-h46w | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-c2j3-45gr-mqc4 | dompurify | DEFER | hook and custom-element config absent | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-52v5-jr5w-gjxr | sigstore | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-vmf3-w455-68vh | tar | DEFER | code not loaded | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-r28c-9q8g-f849 | postcss | DEFER | Node fs stubbed out in the bundle |
Low | 20 (med conf) | 80 | 60 | 180d | ? |
| GHSA-442j-39wm-28r2 | handlebars | DEFER | code not loaded | Low | 20 (med conf) | 80 | 60 | 180d | ? |
| GHSA-7rx3-28cr-v5wh | handlebars | DEFER | code not loaded | Low | 20 (med conf) | 80 | 60 | 180d | ? |
| GHSA-5c6j-r48x-rmvq | serialize-javascript | DEFER | code not loaded | Low | 20 (med conf) | 80 | 60 | 180d | ? |
| GHSA-m9rg-mr6g-75gm | vega-functions | DEFER (build) | no attacker-controlled input | Low | 20 | 80 | 60 | 180d | ? |
| GHSA-vccv-cmxp-4j9h | sanitize-html | DEFER (build) | no attacker-controlled input | Low | 20 | 80 | 60 | 180d | ? |
67 rows covering 66 alerts and 132 verdicts: 64 rows carry one alert scored identically in both contexts, one row groups the 2 alerts sharing GHSA-7f2v-3qq3-vvjf, and 4 rows carry the per-context split on the 2 scheduled alerts. A medium confidence marker means one evidence factor had no real signal; in all four cases here it is Threat, because no KEV or EPSS record exists for that advisory. The reachability half of each of those four is determined.
Appendix: Alert dismissal commands
This appendix is for the operator executing the deferrals: the ready-to-run record.
The alert list supplied for this run carries finding_key, vuln_id, package, and manifest, but no alert numbers and no repository identifier, so no executable command can be emitted. The finding_key values are the durable join key back to the system of record.
Where the system of record is GitHub Dependabot, each deferral takes this form once the alert number is known:
gh api --method PATCH repos/{owner}/{repo}/dependabot/alerts/{alert_number} \
-f state=dismissed \
-f dismissed_reason=not_used \
-f dismissed_comment="<rationale below>"
Use dismissed_reason=not_used for the 55 alerts whose runtime basis is code_not_loaded and dismissed_reason=vulnerable_code_not_actually_used for the 9 whose runtime basis is unreachable_from_entrypoint. The two scheduled alerts are not dismissed.
Rationale text, one per group, each inside GitHub's 280-character ASCII cap for dismissed_comment. State the reachability basis once; restating it in different words spends the budget without adding evidence.
Group 1, 53 alerts (build and release tooling). 190 characters.
k9 rubric v26: DEFER. Not in KEV, EPSS below p90. Basis code_not_loaded: absent from the delivered bundle inventory (jupyterlab/static/third-party-licenses.json); no node_modules ships. Residual Low/20.
Group 2, 2 alerts (lodash GHSA-r5fr-rjxr-66jc, vega-interpreter GHSA-7f2v-3qq3-vvjf). 205 characters.
k9 rubric v26: DEFER. Not in KEV. Basis code_not_loaded: the vulnerable module is absent from the delivered bundle even though the package is in the graph. Residual Low/20. lodash EPSS p97.4, monitor for retrain.
Group 3, 9 alerts (delivered, precondition absent). 232 characters.
k9 rubric v26: DEFER. Not in KEV, EPSS below p90. Basis unreachable_from_entrypoint: the library is delivered and runs on untrusted content, but the advisory's trigger precondition (config option, global, or Node fs) is absent from the build. Residual Low/20.
For @jupyterlab/help-extension GHSA-rch3-82jr-f9w9 specifically, this comment is more accurate at 178 characters:
k9 rubric v26: DEFER. Not in KEV, EPSS p39. Delivered JupyterLab 4.6.2 is past the 4.5.7 fix; the allowCommandLinker patch is present in the shipped bundle and schema. Residual Low/20.
Until alert numbers are available, this report is the durable rationale record. Store it alongside the scan output so the deferral evidence is retrievable at the next review.
