Please report security issues privately via GitHub's "Report a vulnerability" flow rather than opening a public issue.
This theme is deliberately pinned to Remix v1.17 (@remix-run/* ~1.17.0), the same
pin the lecture theme carries and for the same reason. Remix 1.19+ hard-reloads the client
when window.__remixContext.url is undefined — which it always is under the mystmd CLI's
SSR — producing an infinite reload loop and breaking in-page navigation (see the comment
block in .npmrc). Most upstream Remix security advisories are patched only in
the v2 line, so they cannot be resolved without a major migration that re-introduces
that regression. This is a conscious trade-off, inherited with the scaffold and re-triaged
below against this repository's own dependency tree.
Where a vulnerable transitive dependency has a backward-compatible patched release, we
pull it forward with an
overrides entry
in package.json rather than bumping a major version of the toolchain.
Current overrides, each verified to resolve in this tree:
| Package | Forced to | Reason |
|---|---|---|
prismjs |
^1.30.0 |
ReDoS / prototype-pollution advisories |
katex |
^0.16.21 |
matches the rendered KaTeX (vs the CDN's 0.15) |
uuid |
^11.1.1 |
GHSA-w5hq-g745-h8pq |
ajv |
^8.18.0 |
GHSA-2g4f-4pwh-qvx6 |
cookie |
^0.7.0 |
GHSA-pxg6-pf52-xh8x (used via Remix's cookie session) |
shell-quote |
^1.10.0 |
GHSA-w7jw-789q-3m8p (dev; via concurrently) |
brace-expansion@^1.0.0 |
^1.1.18 |
GHSA-3jxr-9vmj-r5cp / GHSA-mh99-v99m-4gvg / GHSA-rgw5-rvv9-x895 — ReDoS-style DoS via exponential expansion; two majors coexist in the tree, so the override is version-scoped |
brace-expansion@^5.0.0 |
^5.0.9 |
same advisory family. Inherited from the lecture theme and currently inert — no 5.x copy resolves in this tree — kept as a forward guard so a future dependency bump cannot reintroduce one silently |
js-yaml@^3.0.0 |
^3.15.0 |
GHSA-52cp-r559-cp3m / GHSA-h67p-54hq-rp68 — quadratic CPU consumption via YAML merge-key chains |
js-yaml@^4.0.0 |
^4.3.0 |
same advisories, 4.x copy |
@babel/core |
^7.29.6 |
GHSA-4x5r-pxfx-6jf8 — arbitrary file read via sourceMappingURL comment (low; build-time) |
Two of the lecture theme's overrides are not carried across, having been re-checked against this tree:
ws— the lecture theme scopes an override to the 8.x copies. Here both copies (7.5.13,8.21.3) are already above their patched floors andnpm auditraises nothing against them, so no override is needed.sanitize-html— the lecture theme pins2.17.5exactly for GHSA-vccv-cmxp-4j9h. Forcing that version here was tested and does not clear the package's advisories (the SVG SMIL scheme-policy bypass is not fixed at 2.17.5 either), and it raises the total alert count by pulling more paths onto the forced copy, so the override is omitted and the advisory is deferred with the rest of the Jupyter chain below.
npm audit fix (without --force) is a no-op for this tree: every remaining advisory
needs either a major bump or a manual override.
Snapshot as of 2026-09-03, taken from npm audit against the committed lockfile:
69 advisories (5 critical, 16 high, 44 moderate, 4 low). Re-evaluate when the theme
migrates off Remix v1.
Every alert is accounted for below. When adding a deferral here, name the package — the buckets are matched by package, so an advisory whose package appears nowhere in this section is an untriaged one, not an implicitly-deferred one.
The migration off Remix v1 is upstream-first and gated on jupyter-book/myst-theme; the
lecture theme tracks it in
quantecon-theme.mystmd#28
and retargeted it from Remix v2 to React Router 7 in June 2026. This theme moves when
that does.
| Package(s) | Severity | Status |
|---|---|---|
@remix-run/node, @remix-run/vercel, @remix-run/express, @remix-run/serve (GHSA-9583-h5hc-x8cw / CVE-2025-61686) |
critical | Not applicable — path traversal in file-backed session storage (createFileSessionStorage), which this theme does not use. The theme's only session is the cookie-backed colour-mode session (createCookieSessionStorage, via @myst-theme/site's getThemeSession in app/root.tsx). |
@remix-run/react, @remix-run/server-runtime, @remix-run/router, react-router, react-router-dom |
high | Patched only in Remix v2 / react-router 6.30+ or 7.18+. @remix-run/react@1.17 exact-pins react-router-dom@6.13.0 and @remix-run/router@1.6.3, which ship paired internal APIs, so the routers cannot be pulled forward independently. Deferred with the v1 pin. |
@remix-run/dev and its build chain — esbuild, vite, vite-node, @vanilla-extract/integration, estree-util-value-to-estree, remark-mdx-frontmatter, cacache, tar |
high/critical | Build-time only, and every fix is @remix-run/dev@2.x. The tar criticals (the 2026 node-tar path-traversal batch) are fixed only in tar 7.5.x, which @remix-run/dev@1.17's cacache chain cannot take. |
@tootallnate/once, proxy-agent, pac-proxy-agent, pac-resolver, http-proxy-agent, get-uri, ip |
low/high | The proxy-agent chain nested under @remix-run/dev. ip is unmaintained and has no patched release at all; the rest move with @remix-run/dev. Dev-time only. |
Transitive dependencies of @myst-theme/site / myst-to-react. Their fixes are
major-version bumps with a high regression risk and low real exposure for a statically
built report site, so they are deferred until the relevant upstream ships them.
| Package(s) | Severity | Status |
|---|---|---|
markdown-it (13→14) and linkify-it |
high | Quadratic-complexity DoS. linkify-it reaches the tree only as a markdown-it dependency, so it moves when markdown-it does. Both are build-time: content is rendered to AST by the myst CLI, not by the deployed site. |
nanoid |
high | Two copies (3.x, 4.x) reach the tree under myst-to-react; fixes are 3.3.8+/5.x, and the 4.x line has no fix. |
myst-demo, myst-to-html, myst-to-jats, myst-transforms, myst-parser, @myst-theme/site |
moderate | Flagged only because they depend on the two above. |
sanitize-html and the @jupyterlab/* / @jupyter-widgets/* / thebe-* chain |
moderate | Present transitively via myst-to-react's demo/renderer dependencies, even though this theme ships no live-compute UI and never mounts a Jupyter widget. The fix is @jupyterlab/apputils majors; see the sanitize-html note above for why the lecture theme's exact pin is not carried across. |
qs, body-parser, express |
moderate | In the bundle's server (template/package.json → @remix-run/express), not in this repository's build. npm audit fix clears them; they are refreshed whenever the template's lockfile is regenerated at release time. |
| Package | Severity | Status |
|---|---|---|
@vercel/node (via esbuild, path-to-regexp) |
high | Present only because server.js uses @remix-run/vercel. The fix is @vercel/node@12, a major bump; nothing in the published bundle uses it (the release zip ships template/server.js, an Express server). Removing the Vercel adapter entirely is worth considering with the Phase 2 shell (#6). |